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 | |
131 // because every SetNeedsBeginFrame will force a redraw. | |
132 bool proactive_begin_frame_wanted = | |
133 state_machine_.ProactiveBeginFrameWantedByImplThread() && | |
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 | 140 |
139 bool should_call_set_needs_begin_frame = | 141 bool should_call_set_needs_begin_frame = |
140 // Always request the BeginFrame immediately if it wasn't needed before. | 142 // Always request the BeginFrame immediately if it wasn't needed before. |
141 (needs_begin_frame && !last_set_needs_begin_frame_) || | 143 (needs_begin_frame && !last_set_needs_begin_frame_) || |
142 // We always need to explicitly request our next BeginFrame. | 144 // We always need to explicitly request our next BeginFrame. |
143 state_machine_.inside_begin_frame(); | 145 (state_machine_.begin_frame_state() == |
danakj
2013/09/17 20:26:19
bool at_end_of_deadline = "this thing" might help
brianderson
2013/09/17 21:08:24
Good suggestion. Done.
| |
146 SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE); | |
144 | 147 |
145 if (should_call_set_needs_begin_frame) { | 148 if (should_call_set_needs_begin_frame) { |
146 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); | 149 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); |
147 last_set_needs_begin_frame_ = needs_begin_frame; | 150 last_set_needs_begin_frame_ = needs_begin_frame; |
148 } | 151 } |
149 | 152 |
150 // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive | 153 // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive |
151 // BeginFrame but aren't requesting one. | 154 // BeginFrame but aren't requesting one. |
152 if (!needs_begin_frame && | 155 if (!last_set_needs_begin_frame_ && |
153 state_machine_.ProactiveBeginFrameWantedByImplThread()) { | 156 state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
154 if (poll_for_draw_triggers_closure_.IsCancelled()) { | 157 if (poll_for_draw_triggers_closure_.IsCancelled()) { |
danakj
2013/09/17 20:26:19
As discussed, DCHECK(!needs_begin_frame) with a co
brianderson
2013/09/17 21:08:24
Done.
| |
155 poll_for_draw_triggers_closure_.Reset( | 158 poll_for_draw_triggers_closure_.Reset( |
156 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, | 159 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, |
157 weak_factory_.GetWeakPtr())); | 160 weak_factory_.GetWeakPtr())); |
158 base::MessageLoop::current()->PostDelayedTask( | 161 base::MessageLoop::current()->PostDelayedTask( |
159 FROM_HERE, | 162 FROM_HERE, |
160 poll_for_draw_triggers_closure_.callback(), | 163 poll_for_draw_triggers_closure_.callback(), |
161 last_begin_frame_args_.interval); | 164 last_begin_frame_args_.interval); |
162 } | 165 } |
163 } else { | 166 } else { |
164 poll_for_draw_triggers_closure_.Cancel(); | 167 poll_for_draw_triggers_closure_.Cancel(); |
165 } | 168 } |
166 } | 169 } |
167 | 170 |
168 void Scheduler::BeginFrame(const BeginFrameArgs& args) { | 171 void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
169 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); | 172 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); |
170 DCHECK(!state_machine_.inside_begin_frame()); | |
danakj
2013/09/17 20:26:19
Can we dcheck against the begin_frame_state() inst
brianderson
2013/09/17 21:08:24
I moved DCHECKS to OnBeginFrame, OnBeginFrameDeadl
| |
171 last_begin_frame_args_ = args; | 173 last_begin_frame_args_ = args; |
172 state_machine_.DidEnterBeginFrame(args); | 174 last_begin_frame_args_.deadline -= client_->DrawDurationEstimate(); |
175 state_machine_.OnBeginFrame(last_begin_frame_args_); | |
173 ProcessScheduledActions(); | 176 ProcessScheduledActions(); |
174 state_machine_.DidLeaveBeginFrame(); | 177 state_machine_.OnBeginFrameDeadlinePending(); |
178 | |
179 if (settings_.using_synchronous_renderer_compositor) { | |
180 // The synchronous renderer compositor has to make its GL calls | |
181 // within this call to BeginFrame. | |
182 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks | |
183 // so the sychronous renderer compoistor can take advantage of splitting | |
184 // up the BeginFrame and deadline as well. | |
185 OnBeginFrameDeadline(); | |
186 } else if (!settings_.deadline_scheduling_enabled) { | |
187 // We emulate the old non-deadline scheduler here by posting the | |
188 // deadline task without any delay. | |
189 PostBeginFrameDeadline(base::TimeTicks()); | |
190 } else if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) { | |
191 // We are ready to draw a new active tree immediately. | |
192 PostBeginFrameDeadline(base::TimeTicks()); | |
193 } else if (state_machine_.needs_redraw()) { | |
194 // We have an animation or fast input path on the impl thread that wants | |
195 // to draw, so don't wait too long for a new active tree. | |
196 PostBeginFrameDeadline(last_begin_frame_args_.deadline); | |
197 } else { | |
198 // The impl thread doesn't have anything it wants to draw and we are just | |
199 // waiting for a new active tree, so post the deadline for the next | |
200 // expected BeginFrame start. This allows us to draw immediately when | |
201 // there is a new active tree, instead of waiting for the next BeginFrame. | |
202 // TODO(brianderson): Handle long deadlines (that are past the next frame's | |
203 // frame time) properly instead of using this hack. | |
204 PostBeginFrameDeadline(last_begin_frame_args_.frame_time + | |
205 last_begin_frame_args_.interval); | |
206 } | |
207 } | |
208 | |
209 void Scheduler::PostBeginFrameDeadline(base::TimeTicks deadline) { | |
210 begin_frame_deadline_closure_.Cancel(); | |
211 begin_frame_deadline_closure_.Reset( | |
212 base::Bind(&Scheduler::OnBeginFrameDeadline, weak_factory_.GetWeakPtr())); | |
213 client_->PostBeginFrameDeadline(begin_frame_deadline_closure_.callback(), | |
214 deadline); | |
215 } | |
216 | |
217 void Scheduler::OnBeginFrameDeadline() { | |
218 TRACE_EVENT0("cc", "Scheduler::OnBeginFrameDeadline"); | |
219 begin_frame_deadline_closure_.Cancel(); | |
220 state_machine_.OnBeginFrameDeadline(); | |
221 ProcessScheduledActions(); | |
222 // We only transition out of BEGIN_FRAME_STATE_INSIDE_DEADLINE when all | |
223 // actions that occur back-to-back in response to entering | |
224 // BEGIN_FRAME_STATE_INSIDE_DEADLINE have completed. This is important | |
225 // because sending the BeginFrame to the main thread will not occur if | |
226 // we transition to BEGIN_FRAME_STATE_IDLE too early. | |
227 state_machine_.OnBeginFrameIdle(); | |
228 client_->DidBeginFrameDeadlineOnImplThread(); | |
175 } | 229 } |
176 | 230 |
177 void Scheduler::PollForAnticipatedDrawTriggers() { | 231 void Scheduler::PollForAnticipatedDrawTriggers() { |
178 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); | 232 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); |
179 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); | 233 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); |
180 ProcessScheduledActions(); | 234 ProcessScheduledActions(); |
181 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); | 235 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); |
182 } | 236 } |
183 | 237 |
184 void Scheduler::DrawAndSwapIfPossible() { | 238 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: | 275 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: |
222 client_->ScheduledActionSendBeginFrameToMainThread(); | 276 client_->ScheduledActionSendBeginFrameToMainThread(); |
223 break; | 277 break; |
224 case SchedulerStateMachine::ACTION_COMMIT: | 278 case SchedulerStateMachine::ACTION_COMMIT: |
225 client_->ScheduledActionCommit(); | 279 client_->ScheduledActionCommit(); |
226 break; | 280 break; |
227 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: | 281 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: |
228 client_->ScheduledActionUpdateVisibleTiles(); | 282 client_->ScheduledActionUpdateVisibleTiles(); |
229 break; | 283 break; |
230 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: | 284 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: |
231 client_->ScheduledActionActivatePendingTree(); | 285 ActivatePendingTree(); |
232 break; | 286 break; |
233 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: | 287 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: |
234 DrawAndSwapIfPossible(); | 288 DrawAndSwapIfPossible(); |
235 break; | 289 break; |
236 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: | 290 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: |
237 DrawAndSwapForced(); | 291 DrawAndSwapForced(); |
238 break; | 292 break; |
239 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: | 293 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: |
240 // No action is actually performed, but this allows the state machine to | 294 // No action is actually performed, but this allows the state machine to |
241 // advance out of its waiting to draw state without actually drawing. | 295 // advance out of its waiting to draw state without actually drawing. |
(...skipping 15 matching lines...) Expand all Loading... | |
257 | 311 |
258 SetupNextBeginFrameIfNeeded(); | 312 SetupNextBeginFrameIfNeeded(); |
259 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); | 313 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); |
260 } | 314 } |
261 | 315 |
262 bool Scheduler::WillDrawIfNeeded() const { | 316 bool Scheduler::WillDrawIfNeeded() const { |
263 return !state_machine_.PendingDrawsShouldBeAborted(); | 317 return !state_machine_.PendingDrawsShouldBeAborted(); |
264 } | 318 } |
265 | 319 |
266 } // namespace cc | 320 } // namespace cc |
OLD | NEW |