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 3 // found in the LICENSE file. 4 5 #include "cc/scheduler/scheduler.h" 6 7 #include <algorithm> 8 #include "base/auto_reset.h" 9 #include "base/debug/trace_event.h" 10 #include "base/logging.h" 11 #include "cc/debug/devtools_instrumentation.h" 12 #include "cc/debug/traced_value.h" 13 #include "ui/gfx/frame_time.h" 14 15 namespace cc { 16 17 Scheduler::Scheduler(SchedulerClient* client, 18 const SchedulerSettings& scheduler_settings, 19 int layer_tree_host_id) 20 : settings_(scheduler_settings), 21 client_(client), 22 layer_tree_host_id_(layer_tree_host_id), 23 last_set_needs_begin_impl_frame_(false), 24 state_machine_(scheduler_settings), 25 inside_process_scheduled_actions_(false), 26 inside_action_(SchedulerStateMachine::ACTION_NONE), 27 weak_factory_(this) { 28 DCHECK(client_); 29 DCHECK(!state_machine_.BeginImplFrameNeeded()); 30 } 31 32 Scheduler::~Scheduler() {} 33 34 void Scheduler::SetCanStart() { 35 state_machine_.SetCanStart(); 36 ProcessScheduledActions(); 37 } 38 39 void Scheduler::SetVisible(bool visible) { 40 state_machine_.SetVisible(visible); 41 ProcessScheduledActions(); 42 } 43 44 void Scheduler::SetCanDraw(bool can_draw) { 45 state_machine_.SetCanDraw(can_draw); 46 ProcessScheduledActions(); 47 } 48 49 void Scheduler::NotifyReadyToActivate() { 50 state_machine_.NotifyReadyToActivate(); 51 ProcessScheduledActions(); 52 } 53 54 void Scheduler::ActivatePendingTree() { 55 client_->ScheduledActionActivatePendingTree(); 56 } 57 58 void Scheduler::SetNeedsCommit() { 59 state_machine_.SetNeedsCommit(); 60 ProcessScheduledActions(); 61 } 62 63 void Scheduler::SetNeedsForcedCommitForReadback() { 64 state_machine_.SetNeedsCommit(); 65 state_machine_.SetNeedsForcedCommitForReadback(); 66 ProcessScheduledActions(); 67 } 68 69 void Scheduler::SetNeedsRedraw() { 70 state_machine_.SetNeedsRedraw(); 71 ProcessScheduledActions(); 72 } 73 74 void Scheduler::SetNeedsManageTiles() { 75 DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES)); 76 state_machine_.SetNeedsManageTiles(); 77 ProcessScheduledActions(); 78 } 79 80 void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) { 81 state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile); 82 ProcessScheduledActions(); 83 } 84 85 void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority) { 86 state_machine_.SetSmoothnessTakesPriority(smoothness_takes_priority); 87 ProcessScheduledActions(); 88 } 89 90 void Scheduler::SetMainThreadNeedsLayerTextures() { 91 state_machine_.SetMainThreadNeedsLayerTextures(); 92 ProcessScheduledActions(); 93 } 94 95 void Scheduler::FinishCommit() { 96 TRACE_EVENT0("cc", "Scheduler::FinishCommit"); 97 state_machine_.FinishCommit(); 98 ProcessScheduledActions(); 99 } 100 101 void Scheduler::BeginMainFrameAborted(bool did_handle) { 102 TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted"); 103 state_machine_.BeginMainFrameAborted(did_handle); 104 ProcessScheduledActions(); 105 } 106 107 void Scheduler::DidManageTiles() { 108 state_machine_.DidManageTiles(); 109 } 110 111 void Scheduler::DidLoseOutputSurface() { 112 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); 113 last_set_needs_begin_impl_frame_ = false; 114 begin_impl_frame_deadline_closure_.Cancel(); 115 state_machine_.DidLoseOutputSurface(); 116 ProcessScheduledActions(); 117 } 118 119 void Scheduler::DidCreateAndInitializeOutputSurface() { 120 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); 121 DCHECK(!last_set_needs_begin_impl_frame_); 122 DCHECK(begin_impl_frame_deadline_closure_.IsCancelled()); 123 state_machine_.DidCreateAndInitializeOutputSurface(); 124 ProcessScheduledActions(); 125 } 126 127 base::TimeTicks Scheduler::AnticipatedDrawTime() { 128 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); 129 130 if (!last_set_needs_begin_impl_frame_ || 131 last_begin_impl_frame_args_.interval <= base::TimeDelta()) 132 return base::TimeTicks(); 133 134 base::TimeTicks now = gfx::FrameTime::Now(); 135 base::TimeTicks timebase = std::max(last_begin_impl_frame_args_.frame_time, 136 last_begin_impl_frame_args_.deadline); 137 int64 intervals = 138 1 + ((now - timebase) / last_begin_impl_frame_args_.interval); 139 return timebase + (last_begin_impl_frame_args_.interval * intervals); 140 } 141 142 base::TimeTicks Scheduler::LastBeginImplFrameTime() { 143 return last_begin_impl_frame_args_.frame_time; 144 } 145 146 void Scheduler::SetupNextBeginImplFrameIfNeeded() { 147 bool needs_begin_impl_frame = 148 state_machine_.BeginImplFrameNeeded(); 149 150 bool at_end_of_deadline = 151 state_machine_.begin_impl_frame_state() == 152 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; 153 154 bool should_call_set_needs_begin_impl_frame = 155 // Always request the BeginImplFrame immediately if it wasn't needed 156 // before. 157 (needs_begin_impl_frame && !last_set_needs_begin_impl_frame_) || 158 // We always need to explicitly request our next BeginImplFrame. 159 at_end_of_deadline; 160 161 if (should_call_set_needs_begin_impl_frame) { 162 client_->SetNeedsBeginImplFrame(needs_begin_impl_frame); 163 last_set_needs_begin_impl_frame_ = needs_begin_impl_frame; 164 } 165 166 bool needs_advance_commit_state_timer = false; 167 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but 168 // aren't expecting any more BeginImplFrames. This should only be needed by 169 // the synchronous compositor when BeginImplFrameNeeded is false. 170 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { 171 DCHECK(!state_machine_.SupportsProactiveBeginImplFrame()); 172 DCHECK(!needs_begin_impl_frame); 173 if (poll_for_draw_triggers_closure_.IsCancelled()) { 174 poll_for_draw_triggers_closure_.Reset( 175 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, 176 weak_factory_.GetWeakPtr())); 177 base::MessageLoop::current()->PostDelayedTask( 178 FROM_HERE, 179 poll_for_draw_triggers_closure_.callback(), 180 last_begin_impl_frame_args_.interval); 181 } 182 } else { 183 poll_for_draw_triggers_closure_.Cancel(); 184 185 // At this point we'd prefer to advance through the commit flow by 186 // drawing a frame, however it's possible that the frame rate controller 187 // will not give us a BeginImplFrame until the commit completes. See 188 // crbug.com/317430 for an example of a swap ack being held on commit. Thus 189 // we set a repeating timer to poll on ProcessScheduledActions until we 190 // successfully reach BeginImplFrame. 191 if (state_machine_.IsCommitStateWaiting()) 192 needs_advance_commit_state_timer = true; 193 } 194 if (needs_advance_commit_state_timer != 195 advance_commit_state_timer_.IsRunning()) { 196 if (needs_advance_commit_state_timer && 197 last_begin_impl_frame_args_.IsValid()) { 198 // Since we'd rather get a BeginImplFrame by the normally mechanism, we set 199 // the interval to twice the interval from the previous frame. 200 advance_commit_state_timer_.Start( 201 FROM_HERE, 202 last_begin_impl_frame_args_.interval * 2, 203 base::Bind(&Scheduler::ProcessScheduledActions, 204 base::Unretained(this))); 205 } else { 206 advance_commit_state_timer_.Stop(); 207 } 208 } 209 } 210 211 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { 212 TRACE_EVENT0("cc", "Scheduler::BeginImplFrame"); 213 DCHECK(state_machine_.begin_impl_frame_state() == 214 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); 215 DCHECK(state_machine_.HasInitializedOutputSurface()); 216 last_begin_impl_frame_args_ = args; 217 last_begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate(); 218 state_machine_.OnBeginImplFrame(last_begin_impl_frame_args_); 219 220 if (settings_.switch_to_low_latency_if_possible) { 221 state_machine_.SetSkipBeginMainFrameToReduceLatency( 222 state_machine_.MainThreadIsInHighLatencyMode() && 223 CanCommitAndActivateBeforeDeadline()); 224 } 225 226 ProcessScheduledActions(); 227 228 if (!state_machine_.HasInitializedOutputSurface()) 229 return; 230 231 state_machine_.OnBeginImplFrameDeadlinePending(); 232 devtools_instrumentation::didBeginFrame(layer_tree_host_id_); 233 if (settings_.using_synchronous_renderer_compositor) { 234 // The synchronous renderer compositor has to make its GL calls 235 // within this call to BeginImplFrame. 236 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks 237 // so the sychronous renderer compositor can take advantage of splitting 238 // up the BeginImplFrame and deadline as well. 239 OnBeginImplFrameDeadline(); 240 } else if (!settings_.deadline_scheduling_enabled) { 241 // We emulate the old non-deadline scheduler here by posting the 242 // deadline task without any delay. 243 PostBeginImplFrameDeadline(base::TimeTicks()); 244 } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { 245 // We are ready to draw a new active tree immediately. 246 PostBeginImplFrameDeadline(base::TimeTicks()); 247 } else if (state_machine_.needs_redraw()) { 248 // We have an animation or fast input path on the impl thread that wants 249 // to draw, so don't wait too long for a new active tree. 250 PostBeginImplFrameDeadline(last_begin_impl_frame_args_.deadline); 251 } else { 252 // The impl thread doesn't have anything it wants to draw and we are just 253 // waiting for a new active tree, so post the deadline for the next 254 // expected BeginImplFrame start. This allows us to draw immediately when 255 // there is a new active tree, instead of waiting for the next 256 // BeginImplFrame. 257 // TODO(brianderson): Handle long deadlines (that are past the next frame's 258 // frame time) properly instead of using this hack. 259 PostBeginImplFrameDeadline(last_begin_impl_frame_args_.frame_time + 260 last_begin_impl_frame_args_.interval); 261 } 262 } 263 264 void Scheduler::PostBeginImplFrameDeadline(base::TimeTicks deadline) { 265 begin_impl_frame_deadline_closure_.Cancel(); 266 begin_impl_frame_deadline_closure_.Reset( 267 base::Bind(&Scheduler::OnBeginImplFrameDeadline, 268 weak_factory_.GetWeakPtr())); 269 client_->PostBeginImplFrameDeadline( 270 begin_impl_frame_deadline_closure_.callback(), deadline); 271 } 272 273 void Scheduler::OnBeginImplFrameDeadline() { 274 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); 275 DCHECK(state_machine_.HasInitializedOutputSurface()); 276 begin_impl_frame_deadline_closure_.Cancel(); 277 state_machine_.OnBeginImplFrameDeadline(); 278 ProcessScheduledActions(); 279 280 if (state_machine_.HasInitializedOutputSurface()) { 281 // We only transition out of BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE when all 282 // actions that occur back-to-back in response to entering 283 // BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE have completed. This is important 284 // because sending the BeginMainFrame will not occur if we transition to 285 // BEGIN_IMPL_FRAME_STATE_IDLE too early. 286 state_machine_.OnBeginImplFrameIdle(); 287 } 288 289 client_->DidBeginImplFrameDeadline(); 290 } 291 292 void Scheduler::PollForAnticipatedDrawTriggers() { 293 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); 294 poll_for_draw_triggers_closure_.Cancel(); 295 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); 296 ProcessScheduledActions(); 297 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); 298 } 299 300 void Scheduler::DrawAndSwapIfPossible() { 301 DrawSwapReadbackResult result = 302 client_->ScheduledActionDrawAndSwapIfPossible(); 303 state_machine_.DidDrawIfPossibleCompleted(result.did_draw); 304 } 305 306 void Scheduler::DrawAndSwapForced() { 307 client_->ScheduledActionDrawAndSwapForced(); 308 } 309 310 void Scheduler::DrawAndReadback() { 311 DrawSwapReadbackResult result = client_->ScheduledActionDrawAndReadback(); 312 DCHECK(!result.did_swap); 313 } 314 315 void Scheduler::ProcessScheduledActions() { 316 // We do not allow ProcessScheduledActions to be recursive. 317 // The top-level call will iteratively execute the next action for us anyway. 318 if (inside_process_scheduled_actions_) 319 return; 320 321 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true); 322 323 SchedulerStateMachine::Action action; 324 do { 325 state_machine_.CheckInvariants(); 326 action = state_machine_.NextAction(); 327 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), 328 "SchedulerStateMachine", 329 "state", 330 TracedValue::FromValue(state_machine_.AsValue().release())); 331 state_machine_.UpdateState(action); 332 base::AutoReset<SchedulerStateMachine::Action> 333 mark_inside_action(&inside_action_, action); 334 switch (action) { 335 case SchedulerStateMachine::ACTION_NONE: 336 break; 337 case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: 338 client_->ScheduledActionSendBeginMainFrame(); 339 break; 340 case SchedulerStateMachine::ACTION_COMMIT: 341 client_->ScheduledActionCommit(); 342 break; 343 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: 344 client_->ScheduledActionUpdateVisibleTiles(); 345 break; 346 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: 347 ActivatePendingTree(); 348 break; 349 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: 350 DrawAndSwapIfPossible(); 351 break; 352 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: 353 DrawAndSwapForced(); 354 break; 355 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: 356 // No action is actually performed, but this allows the state machine to 357 // advance out of its waiting to draw state without actually drawing. 358 break; 359 case SchedulerStateMachine::ACTION_DRAW_AND_READBACK: 360 DrawAndReadback(); 361 break; 362 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: 363 client_->ScheduledActionBeginOutputSurfaceCreation(); 364 break; 365 case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD: 366 client_->ScheduledActionAcquireLayerTexturesForMainThread(); 367 break; 368 case SchedulerStateMachine::ACTION_MANAGE_TILES: 369 client_->ScheduledActionManageTiles(); 370 break; 371 } 372 } while (action != SchedulerStateMachine::ACTION_NONE); 373 374 SetupNextBeginImplFrameIfNeeded(); 375 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); 376 377 if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) 378 PostBeginImplFrameDeadline(base::TimeTicks()); 379 } 380 381 bool Scheduler::WillDrawIfNeeded() const { 382 return !state_machine_.PendingDrawsShouldBeAborted(); 383 } 384 385 bool Scheduler::CanCommitAndActivateBeforeDeadline() const { 386 // Check if the main thread computation and commit can be finished before the 387 // impl thread's deadline. 388 base::TimeTicks estimated_draw_time = 389 last_begin_impl_frame_args_.frame_time + 390 client_->BeginMainFrameToCommitDurationEstimate() + 391 client_->CommitToActivateDurationEstimate(); 392 393 return estimated_draw_time < last_begin_impl_frame_args_.deadline; 394 } 395 396 } // namespace cc 397