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 "base/auto_reset.h" | 8 #include "base/auto_reset.h" |
8 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
9 #include "base/logging.h" | 10 #include "base/logging.h" |
10 #include "cc/debug/traced_value.h" | 11 #include "cc/debug/traced_value.h" |
11 | 12 |
12 namespace cc { | 13 namespace cc { |
13 | 14 |
14 Scheduler::Scheduler(SchedulerClient* client, | 15 Scheduler::Scheduler(SchedulerClient* client, |
15 const SchedulerSettings& scheduler_settings) | 16 const SchedulerSettings& scheduler_settings) |
16 : settings_(scheduler_settings), | 17 : settings_(scheduler_settings), |
17 client_(client), | 18 client_(client), |
18 weak_factory_(this), | 19 weak_factory_(this), |
19 last_set_needs_begin_frame_(false), | 20 last_set_needs_begin_frame_(false), |
20 state_machine_(scheduler_settings), | 21 state_machine_(scheduler_settings), |
21 inside_process_scheduled_actions_(false), | 22 inside_process_scheduled_actions_(false), |
22 inside_action_(SchedulerStateMachine::ACTION_NONE) { | 23 inside_action_(SchedulerStateMachine::ACTION_NONE) { |
23 DCHECK(client_); | 24 DCHECK(client_); |
24 DCHECK(!state_machine_.BeginFrameNeededToDrawByImplThread()); | 25 DCHECK(!state_machine_.BeginFrameNeededByImplThread()); |
25 } | 26 } |
26 | 27 |
27 Scheduler::~Scheduler() { | 28 Scheduler::~Scheduler() {} |
28 client_->SetNeedsBeginFrameOnImplThread(false); | |
29 } | |
30 | 29 |
31 void Scheduler::SetCanStart() { | 30 void Scheduler::SetCanStart() { |
32 state_machine_.SetCanStart(); | 31 state_machine_.SetCanStart(); |
33 ProcessScheduledActions(); | 32 ProcessScheduledActions(); |
34 } | 33 } |
35 | 34 |
36 void Scheduler::SetVisible(bool visible) { | 35 void Scheduler::SetVisible(bool visible) { |
37 state_machine_.SetVisible(visible); | 36 state_machine_.SetVisible(visible); |
38 ProcessScheduledActions(); | 37 ProcessScheduledActions(); |
39 } | 38 } |
40 | 39 |
41 void Scheduler::SetCanDraw(bool can_draw) { | 40 void Scheduler::SetCanDraw(bool can_draw) { |
42 state_machine_.SetCanDraw(can_draw); | 41 state_machine_.SetCanDraw(can_draw); |
43 ProcessScheduledActions(); | 42 ProcessScheduledActions(); |
44 } | 43 } |
45 | 44 |
46 void Scheduler::NotifyReadyToActivate() { | 45 void Scheduler::NotifyReadyToActivate() { |
47 state_machine_.NotifyReadyToActivate(); | 46 state_machine_.NotifyReadyToActivate(); |
48 ProcessScheduledActions(); | 47 ProcessScheduledActions(); |
49 } | 48 } |
50 | 49 |
| 50 void Scheduler::ActivatePendingTree() { |
| 51 client_->ScheduledActionActivatePendingTree(); |
| 52 if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) |
| 53 PostBeginFrameDeadline(base::TimeTicks()); |
| 54 } |
| 55 |
51 void Scheduler::SetNeedsCommit() { | 56 void Scheduler::SetNeedsCommit() { |
52 state_machine_.SetNeedsCommit(); | 57 state_machine_.SetNeedsCommit(); |
53 ProcessScheduledActions(); | 58 ProcessScheduledActions(); |
54 } | 59 } |
55 | 60 |
56 void Scheduler::SetNeedsForcedCommitForReadback() { | 61 void Scheduler::SetNeedsForcedCommitForReadback() { |
57 state_machine_.SetNeedsCommit(); | 62 state_machine_.SetNeedsCommit(); |
58 state_machine_.SetNeedsForcedCommitForReadback(); | 63 state_machine_.SetNeedsForcedCommitForReadback(); |
59 ProcessScheduledActions(); | 64 ProcessScheduledActions(); |
60 } | 65 } |
(...skipping 16 matching lines...) Expand all Loading... |
77 | 82 |
78 void Scheduler::SetMainThreadNeedsLayerTextures() { | 83 void Scheduler::SetMainThreadNeedsLayerTextures() { |
79 state_machine_.SetMainThreadNeedsLayerTextures(); | 84 state_machine_.SetMainThreadNeedsLayerTextures(); |
80 ProcessScheduledActions(); | 85 ProcessScheduledActions(); |
81 } | 86 } |
82 | 87 |
83 void Scheduler::FinishCommit() { | 88 void Scheduler::FinishCommit() { |
84 TRACE_EVENT0("cc", "Scheduler::FinishCommit"); | 89 TRACE_EVENT0("cc", "Scheduler::FinishCommit"); |
85 state_machine_.FinishCommit(); | 90 state_machine_.FinishCommit(); |
86 ProcessScheduledActions(); | 91 ProcessScheduledActions(); |
| 92 |
| 93 if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) |
| 94 PostBeginFrameDeadline(base::TimeTicks()); |
87 } | 95 } |
88 | 96 |
89 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { | 97 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { |
90 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread"); | 98 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread"); |
91 state_machine_.BeginFrameAbortedByMainThread(did_handle); | 99 state_machine_.BeginFrameAbortedByMainThread(did_handle); |
92 ProcessScheduledActions(); | 100 ProcessScheduledActions(); |
93 } | 101 } |
94 | 102 |
95 void Scheduler::DidLoseOutputSurface() { | 103 void Scheduler::DidLoseOutputSurface() { |
96 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); | 104 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); |
| 105 last_set_needs_begin_frame_ = false; |
| 106 begin_frame_deadline_closure_.Cancel(); |
97 state_machine_.DidLoseOutputSurface(); | 107 state_machine_.DidLoseOutputSurface(); |
98 ProcessScheduledActions(); | 108 ProcessScheduledActions(); |
99 } | 109 } |
100 | 110 |
101 void Scheduler::DidCreateAndInitializeOutputSurface() { | 111 void Scheduler::DidCreateAndInitializeOutputSurface() { |
102 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); | 112 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); |
| 113 DCHECK(!last_set_needs_begin_frame_); |
| 114 DCHECK(begin_frame_deadline_closure_.IsCancelled()); |
103 state_machine_.DidCreateAndInitializeOutputSurface(); | 115 state_machine_.DidCreateAndInitializeOutputSurface(); |
104 last_set_needs_begin_frame_ = false; | |
105 ProcessScheduledActions(); | 116 ProcessScheduledActions(); |
106 } | 117 } |
107 | 118 |
108 base::TimeTicks Scheduler::AnticipatedDrawTime() { | 119 base::TimeTicks Scheduler::AnticipatedDrawTime() { |
109 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); | 120 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); |
110 | 121 |
111 if (!last_set_needs_begin_frame_ || | 122 if (!last_set_needs_begin_frame_ || |
112 last_begin_frame_args_.interval <= base::TimeDelta()) | 123 last_begin_frame_args_.interval <= base::TimeDelta()) |
113 return base::TimeTicks(); | 124 return base::TimeTicks(); |
114 | 125 |
115 // TODO(brianderson): Express this in terms of the deadline. | |
116 base::TimeTicks now = base::TimeTicks::Now(); | 126 base::TimeTicks now = base::TimeTicks::Now(); |
117 int64 intervals = 1 + ((now - last_begin_frame_args_.frame_time) / | 127 base::TimeTicks timebase = std::max(last_begin_frame_args_.frame_time, |
118 last_begin_frame_args_.interval); | 128 last_begin_frame_args_.deadline); |
119 return last_begin_frame_args_.frame_time + | 129 int64 intervals = 1 + ((now - timebase) / last_begin_frame_args_.interval); |
120 (last_begin_frame_args_.interval * intervals); | 130 return timebase + (last_begin_frame_args_.interval * intervals); |
121 } | 131 } |
122 | 132 |
123 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { | 133 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { |
124 return last_begin_frame_args_.frame_time; | 134 return last_begin_frame_args_.frame_time; |
125 } | 135 } |
126 | 136 |
127 void Scheduler::SetupNextBeginFrameIfNeeded() { | 137 void Scheduler::SetupNextBeginFrameIfNeeded() { |
128 bool needs_begin_frame_to_draw = | 138 bool needs_begin_frame = |
129 state_machine_.BeginFrameNeededToDrawByImplThread(); | 139 state_machine_.BeginFrameNeededByImplThread(); |
130 // We want to avoid proactive begin frames with the synchronous compositor | 140 |
131 // because every SetNeedsBeginFrame will force a redraw. | 141 bool at_end_of_deadline = |
132 bool proactive_begin_frame_wanted = | 142 state_machine_.begin_frame_state() == |
133 state_machine_.ProactiveBeginFrameWantedByImplThread() && | 143 SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE; |
134 !settings_.using_synchronous_renderer_compositor && | |
135 settings_.throttle_frame_production; | |
136 bool needs_begin_frame = needs_begin_frame_to_draw || | |
137 proactive_begin_frame_wanted; | |
138 | 144 |
139 bool should_call_set_needs_begin_frame = | 145 bool should_call_set_needs_begin_frame = |
140 // Always request the BeginFrame immediately if it wasn't needed before. | 146 // Always request the BeginFrame immediately if it wasn't needed before. |
141 (needs_begin_frame && !last_set_needs_begin_frame_) || | 147 (needs_begin_frame && !last_set_needs_begin_frame_) || |
142 // We always need to explicitly request our next BeginFrame. | 148 // We always need to explicitly request our next BeginFrame. |
143 state_machine_.inside_begin_frame(); | 149 at_end_of_deadline; |
144 | 150 |
145 if (should_call_set_needs_begin_frame) { | 151 if (should_call_set_needs_begin_frame) { |
146 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); | 152 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); |
147 last_set_needs_begin_frame_ = needs_begin_frame; | 153 last_set_needs_begin_frame_ = needs_begin_frame; |
148 } | 154 } |
149 | 155 |
150 // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive | 156 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but |
151 // BeginFrame but aren't requesting one. | 157 // aren't expecting any more BeginFrames. This should only be needed by the |
152 if (!needs_begin_frame && | 158 // synchronous compositor when BeginFrameNeededByImplThread is false. |
153 state_machine_.ProactiveBeginFrameWantedByImplThread()) { | 159 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
| 160 DCHECK(settings_.using_synchronous_renderer_compositor); |
| 161 DCHECK(!needs_begin_frame); |
154 if (poll_for_draw_triggers_closure_.IsCancelled()) { | 162 if (poll_for_draw_triggers_closure_.IsCancelled()) { |
155 poll_for_draw_triggers_closure_.Reset( | 163 poll_for_draw_triggers_closure_.Reset( |
156 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, | 164 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, |
157 weak_factory_.GetWeakPtr())); | 165 weak_factory_.GetWeakPtr())); |
158 base::MessageLoop::current()->PostDelayedTask( | 166 base::MessageLoop::current()->PostDelayedTask( |
159 FROM_HERE, | 167 FROM_HERE, |
160 poll_for_draw_triggers_closure_.callback(), | 168 poll_for_draw_triggers_closure_.callback(), |
161 last_begin_frame_args_.interval); | 169 last_begin_frame_args_.interval); |
162 } | 170 } |
163 } else { | 171 } else { |
164 poll_for_draw_triggers_closure_.Cancel(); | 172 poll_for_draw_triggers_closure_.Cancel(); |
165 } | 173 } |
166 } | 174 } |
167 | 175 |
168 void Scheduler::BeginFrame(const BeginFrameArgs& args) { | 176 void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
169 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); | 177 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); |
170 DCHECK(!state_machine_.inside_begin_frame()); | 178 DCHECK(state_machine_.begin_frame_state() == |
| 179 SchedulerStateMachine::BEGIN_FRAME_STATE_IDLE); |
171 last_begin_frame_args_ = args; | 180 last_begin_frame_args_ = args; |
172 state_machine_.DidEnterBeginFrame(args); | 181 last_begin_frame_args_.deadline -= client_->DrawDurationEstimate(); |
| 182 state_machine_.OnBeginFrame(last_begin_frame_args_); |
173 ProcessScheduledActions(); | 183 ProcessScheduledActions(); |
174 state_machine_.DidLeaveBeginFrame(); | 184 state_machine_.OnBeginFrameDeadlinePending(); |
| 185 |
| 186 if (settings_.using_synchronous_renderer_compositor) { |
| 187 // The synchronous renderer compositor has to make its GL calls |
| 188 // within this call to BeginFrame. |
| 189 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks |
| 190 // so the sychronous renderer compoistor can take advantage of splitting |
| 191 // up the BeginFrame and deadline as well. |
| 192 OnBeginFrameDeadline(); |
| 193 } else if (!settings_.deadline_scheduling_enabled) { |
| 194 // We emulate the old non-deadline scheduler here by posting the |
| 195 // deadline task without any delay. |
| 196 PostBeginFrameDeadline(base::TimeTicks()); |
| 197 } else if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) { |
| 198 // We are ready to draw a new active tree immediately. |
| 199 PostBeginFrameDeadline(base::TimeTicks()); |
| 200 } else if (state_machine_.needs_redraw()) { |
| 201 // We have an animation or fast input path on the impl thread that wants |
| 202 // to draw, so don't wait too long for a new active tree. |
| 203 PostBeginFrameDeadline(last_begin_frame_args_.deadline); |
| 204 } else { |
| 205 // The impl thread doesn't have anything it wants to draw and we are just |
| 206 // waiting for a new active tree, so post the deadline for the next |
| 207 // expected BeginFrame start. This allows us to draw immediately when |
| 208 // there is a new active tree, instead of waiting for the next BeginFrame. |
| 209 // TODO(brianderson): Handle long deadlines (that are past the next frame's |
| 210 // frame time) properly instead of using this hack. |
| 211 PostBeginFrameDeadline(last_begin_frame_args_.frame_time + |
| 212 last_begin_frame_args_.interval); |
| 213 } |
| 214 } |
| 215 |
| 216 void Scheduler::PostBeginFrameDeadline(base::TimeTicks deadline) { |
| 217 begin_frame_deadline_closure_.Cancel(); |
| 218 begin_frame_deadline_closure_.Reset( |
| 219 base::Bind(&Scheduler::OnBeginFrameDeadline, weak_factory_.GetWeakPtr())); |
| 220 client_->PostBeginFrameDeadline(begin_frame_deadline_closure_.callback(), |
| 221 deadline); |
| 222 } |
| 223 |
| 224 void Scheduler::OnBeginFrameDeadline() { |
| 225 TRACE_EVENT0("cc", "Scheduler::OnBeginFrameDeadline"); |
| 226 begin_frame_deadline_closure_.Cancel(); |
| 227 state_machine_.OnBeginFrameDeadline(); |
| 228 ProcessScheduledActions(); |
| 229 // We only transition out of BEGIN_FRAME_STATE_INSIDE_DEADLINE when all |
| 230 // actions that occur back-to-back in response to entering |
| 231 // BEGIN_FRAME_STATE_INSIDE_DEADLINE have completed. This is important |
| 232 // because sending the BeginFrame to the main thread will not occur if |
| 233 // we transition to BEGIN_FRAME_STATE_IDLE too early. |
| 234 state_machine_.OnBeginFrameIdle(); |
| 235 client_->DidBeginFrameDeadlineOnImplThread(); |
175 } | 236 } |
176 | 237 |
177 void Scheduler::PollForAnticipatedDrawTriggers() { | 238 void Scheduler::PollForAnticipatedDrawTriggers() { |
178 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); | 239 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); |
179 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); | 240 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); |
180 ProcessScheduledActions(); | 241 ProcessScheduledActions(); |
181 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); | 242 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); |
182 } | 243 } |
183 | 244 |
184 void Scheduler::DrawAndSwapIfPossible() { | 245 void Scheduler::DrawAndSwapIfPossible() { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: | 282 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: |
222 client_->ScheduledActionSendBeginFrameToMainThread(); | 283 client_->ScheduledActionSendBeginFrameToMainThread(); |
223 break; | 284 break; |
224 case SchedulerStateMachine::ACTION_COMMIT: | 285 case SchedulerStateMachine::ACTION_COMMIT: |
225 client_->ScheduledActionCommit(); | 286 client_->ScheduledActionCommit(); |
226 break; | 287 break; |
227 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: | 288 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: |
228 client_->ScheduledActionUpdateVisibleTiles(); | 289 client_->ScheduledActionUpdateVisibleTiles(); |
229 break; | 290 break; |
230 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: | 291 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: |
231 client_->ScheduledActionActivatePendingTree(); | 292 ActivatePendingTree(); |
232 break; | 293 break; |
233 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: | 294 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: |
234 DrawAndSwapIfPossible(); | 295 DrawAndSwapIfPossible(); |
235 break; | 296 break; |
236 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: | 297 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: |
237 DrawAndSwapForced(); | 298 DrawAndSwapForced(); |
238 break; | 299 break; |
239 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: | 300 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: |
240 // No action is actually performed, but this allows the state machine to | 301 // No action is actually performed, but this allows the state machine to |
241 // advance out of its waiting to draw state without actually drawing. | 302 // advance out of its waiting to draw state without actually drawing. |
(...skipping 15 matching lines...) Expand all Loading... |
257 | 318 |
258 SetupNextBeginFrameIfNeeded(); | 319 SetupNextBeginFrameIfNeeded(); |
259 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); | 320 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); |
260 } | 321 } |
261 | 322 |
262 bool Scheduler::WillDrawIfNeeded() const { | 323 bool Scheduler::WillDrawIfNeeded() const { |
263 return !state_machine_.PendingDrawsShouldBeAborted(); | 324 return !state_machine_.PendingDrawsShouldBeAborted(); |
264 } | 325 } |
265 | 326 |
266 } // namespace cc | 327 } // namespace cc |
OLD | NEW |