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 "base/auto_reset.h" 8 #include "base/debug/trace_event.h" 9 #include "base/logging.h" 10 11 namespace cc { 12 13 Scheduler::Scheduler(SchedulerClient* client, 14 const SchedulerSettings& scheduler_settings) 15 : settings_(scheduler_settings), 16 client_(client), 17 weak_factory_(this), 18 last_set_needs_begin_frame_(false), 19 has_pending_begin_frame_(false), 20 safe_to_expect_begin_frame_(false), 21 state_machine_(scheduler_settings), 22 inside_process_scheduled_actions_(false) { 23 DCHECK(client_); 24 DCHECK(!state_machine_.BeginFrameNeededToDrawByImplThread()); 25 } 26 27 Scheduler::~Scheduler() { 28 client_->SetNeedsBeginFrameOnImplThread(false); 29 } 30 31 void Scheduler::SetCanStart() { 32 state_machine_.SetCanStart(); 33 ProcessScheduledActions(); 34 } 35 36 void Scheduler::SetVisible(bool visible) { 37 state_machine_.SetVisible(visible); 38 ProcessScheduledActions(); 39 } 40 41 void Scheduler::SetCanDraw(bool can_draw) { 42 state_machine_.SetCanDraw(can_draw); 43 ProcessScheduledActions(); 44 } 45 46 void Scheduler::SetHasPendingTree(bool has_pending_tree) { 47 state_machine_.SetHasPendingTree(has_pending_tree); 48 ProcessScheduledActions(); 49 } 50 51 void Scheduler::SetNeedsCommit() { 52 state_machine_.SetNeedsCommit(); 53 ProcessScheduledActions(); 54 } 55 56 void Scheduler::SetNeedsForcedCommit() { 57 state_machine_.SetNeedsCommit(); 58 state_machine_.SetNeedsForcedCommit(); 59 ProcessScheduledActions(); 60 } 61 62 void Scheduler::SetNeedsRedraw() { 63 state_machine_.SetNeedsRedraw(); 64 ProcessScheduledActions(); 65 } 66 67 void Scheduler::DidSwapUseIncompleteTile() { 68 state_machine_.DidSwapUseIncompleteTile(); 69 ProcessScheduledActions(); 70 } 71 72 void Scheduler::SetNeedsForcedRedraw() { 73 state_machine_.SetNeedsForcedRedraw(); 74 ProcessScheduledActions(); 75 } 76 77 void Scheduler::SetMainThreadNeedsLayerTextures() { 78 state_machine_.SetMainThreadNeedsLayerTextures(); 79 ProcessScheduledActions(); 80 } 81 82 void Scheduler::FinishCommit() { 83 TRACE_EVENT0("cc", "Scheduler::FinishCommit"); 84 state_machine_.FinishCommit(); 85 ProcessScheduledActions(); 86 } 87 88 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { 89 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread"); 90 state_machine_.BeginFrameAbortedByMainThread(did_handle); 91 ProcessScheduledActions(); 92 } 93 94 void Scheduler::DidLoseOutputSurface() { 95 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); 96 state_machine_.DidLoseOutputSurface(); 97 ProcessScheduledActions(); 98 } 99 100 void Scheduler::DidCreateAndInitializeOutputSurface() { 101 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); 102 state_machine_.DidCreateAndInitializeOutputSurface(); 103 has_pending_begin_frame_ = false; 104 last_set_needs_begin_frame_ = false; 105 safe_to_expect_begin_frame_ = false; 106 ProcessScheduledActions(); 107 } 108 109 base::TimeTicks Scheduler::AnticipatedDrawTime() { 110 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); 111 112 if (!last_set_needs_begin_frame_ || 113 last_begin_frame_args_.interval <= base::TimeDelta()) 114 return base::TimeTicks(); 115 116 // TODO(brianderson): Express this in terms of the deadline. 117 base::TimeTicks now = base::TimeTicks::Now(); 118 int64 intervals = 1 + ((now - last_begin_frame_args_.frame_time) / 119 last_begin_frame_args_.interval); 120 return last_begin_frame_args_.frame_time + 121 (last_begin_frame_args_.interval * intervals); 122 } 123 124 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { 125 return last_begin_frame_args_.frame_time; 126 } 127 128 void Scheduler::SetupNextBeginFrameIfNeeded() { 129 bool needs_begin_frame_to_draw = 130 state_machine_.BeginFrameNeededToDrawByImplThread(); 131 // We want to avoid proactive begin frames with the synchronous compositor 132 // because every SetNeedsBeginFrame will force a redraw. 133 bool proactive_begin_frame_wanted = 134 state_machine_.ProactiveBeginFrameWantedByImplThread() && 135 !settings_.using_synchronous_renderer_compositor && 136 settings_.throttle_frame_production; 137 bool needs_begin_frame = needs_begin_frame_to_draw || 138 proactive_begin_frame_wanted; 139 bool immediate_disables_needed = 140 settings_.using_synchronous_renderer_compositor; 141 142 if (needs_begin_frame_to_draw) 143 safe_to_expect_begin_frame_ = true; 144 145 // Determine if we need BeginFrame notifications. 146 // If we do, always request the BeginFrame immediately. 147 // If not, only disable on the next BeginFrame to avoid unnecessary toggles. 148 // The synchronous renderer compositor requires immediate disables though. 149 if ((needs_begin_frame || 150 state_machine_.inside_begin_frame() || 151 immediate_disables_needed) && 152 (needs_begin_frame != last_set_needs_begin_frame_)) { 153 has_pending_begin_frame_ = false; 154 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); 155 if (safe_to_expect_begin_frame_) 156 last_set_needs_begin_frame_ = needs_begin_frame; 157 } 158 159 // Request another BeginFrame if we haven't drawn for now until we have 160 // deadlines implemented. 161 if (state_machine_.inside_begin_frame() && has_pending_begin_frame_) { 162 has_pending_begin_frame_ = false; 163 client_->SetNeedsBeginFrameOnImplThread(true); 164 } 165 166 // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive 167 // BeginFrame but aren't requesting one. 168 if (!needs_begin_frame && 169 state_machine_.ProactiveBeginFrameWantedByImplThread()) { 170 if (poll_for_draw_triggers_closure_.IsCancelled()) { 171 poll_for_draw_triggers_closure_.Reset( 172 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, 173 weak_factory_.GetWeakPtr())); 174 base::MessageLoop::current()->PostDelayedTask( 175 FROM_HERE, 176 poll_for_draw_triggers_closure_.callback(), 177 last_begin_frame_args_.interval); 178 } 179 } else { 180 poll_for_draw_triggers_closure_.Cancel(); 181 } 182 } 183 184 void Scheduler::BeginFrame(const BeginFrameArgs& args) { 185 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); 186 DCHECK(!has_pending_begin_frame_); 187 has_pending_begin_frame_ = true; 188 safe_to_expect_begin_frame_ = true; 189 last_begin_frame_args_ = args; 190 state_machine_.DidEnterBeginFrame(args); 191 ProcessScheduledActions(); 192 state_machine_.DidLeaveBeginFrame(); 193 } 194 195 void Scheduler::PollForAnticipatedDrawTriggers() { 196 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); 197 state_machine_.PollForAnticipatedDrawTriggers(); 198 ProcessScheduledActions(); 199 200 poll_for_draw_triggers_closure_.Cancel(); 201 } 202 203 void Scheduler::DrawAndSwapIfPossible() { 204 ScheduledActionDrawAndSwapResult result = 205 client_->ScheduledActionDrawAndSwapIfPossible(); 206 state_machine_.DidDrawIfPossibleCompleted(result.did_draw); 207 if (result.did_swap) 208 has_pending_begin_frame_ = false; 209 } 210 211 void Scheduler::DrawAndSwapForced() { 212 ScheduledActionDrawAndSwapResult result = 213 client_->ScheduledActionDrawAndSwapForced(); 214 if (result.did_swap) 215 has_pending_begin_frame_ = false; 216 } 217 218 void Scheduler::ProcessScheduledActions() { 219 // We do not allow ProcessScheduledActions to be recursive. 220 // The top-level call will iteratively execute the next action for us anyway. 221 if (inside_process_scheduled_actions_) 222 return; 223 224 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true); 225 226 SchedulerStateMachine::Action action = state_machine_.NextAction(); 227 while (action != SchedulerStateMachine::ACTION_NONE) { 228 state_machine_.UpdateState(action); 229 switch (action) { 230 case SchedulerStateMachine::ACTION_NONE: 231 break; 232 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: 233 client_->ScheduledActionSendBeginFrameToMainThread(); 234 break; 235 case SchedulerStateMachine::ACTION_COMMIT: 236 client_->ScheduledActionCommit(); 237 break; 238 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: 239 client_->ScheduledActionUpdateVisibleTiles(); 240 break; 241 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED: 242 client_->ScheduledActionActivatePendingTreeIfNeeded(); 243 break; 244 case SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE: 245 DrawAndSwapIfPossible(); 246 break; 247 case SchedulerStateMachine::ACTION_DRAW_FORCED: 248 DrawAndSwapForced(); 249 break; 250 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: 251 client_->ScheduledActionBeginOutputSurfaceCreation(); 252 break; 253 case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD: 254 client_->ScheduledActionAcquireLayerTexturesForMainThread(); 255 break; 256 } 257 action = state_machine_.NextAction(); 258 } 259 260 SetupNextBeginFrameIfNeeded(); 261 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); 262 } 263 264 bool Scheduler::WillDrawIfNeeded() const { 265 return !state_machine_.DrawSuspendedUntilCommit(); 266 } 267 268 } // namespace cc 269