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

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

Issue 16871016: cc: Use BeginFrameArgs (Closed) Base URL: http://git.chromium.org/chromium/src.git@bfargs2
Patch Set: Add an --enable-deadline-scheduler commandline flag. Created 7 years, 4 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 "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 11
11 namespace cc { 12 namespace cc {
12 13
13 Scheduler::Scheduler(SchedulerClient* client, 14 Scheduler::Scheduler(SchedulerClient* client,
14 const SchedulerSettings& scheduler_settings) 15 const SchedulerSettings& scheduler_settings)
15 : settings_(scheduler_settings), 16 : settings_(scheduler_settings),
16 client_(client), 17 client_(client),
17 weak_factory_(this), 18 weak_factory_(this),
18 last_set_needs_begin_frame_(false), 19 last_set_needs_begin_frame_(false),
19 has_pending_begin_frame_(false), 20 has_pending_begin_frame_(false),
20 safe_to_expect_begin_frame_(false), 21 safe_to_expect_begin_frame_(
22 !scheduler_settings.use_begin_frame_workaround_for_crbug_249806),
21 state_machine_(scheduler_settings), 23 state_machine_(scheduler_settings),
22 inside_process_scheduled_actions_(false) { 24 inside_process_scheduled_actions_(false) {
23 DCHECK(client_); 25 DCHECK(client_);
24 DCHECK(!state_machine_.BeginFrameNeededToDrawByImplThread()); 26 DCHECK(!state_machine_.BeginFrameNeededByImplThread());
25 } 27 }
26 28
27 Scheduler::~Scheduler() { 29 Scheduler::~Scheduler() {
28 client_->SetNeedsBeginFrameOnImplThread(false); 30 client_->SetNeedsBeginFrameOnImplThread(false);
29 } 31 }
30 32
31 void Scheduler::SetCanStart() { 33 void Scheduler::SetCanStart() {
32 state_machine_.SetCanStart(); 34 state_machine_.SetCanStart();
33 ProcessScheduledActions(); 35 ProcessScheduledActions();
34 } 36 }
35 37
36 void Scheduler::SetVisible(bool visible) { 38 void Scheduler::SetVisible(bool visible) {
37 state_machine_.SetVisible(visible); 39 state_machine_.SetVisible(visible);
38 ProcessScheduledActions(); 40 ProcessScheduledActions();
39 } 41 }
40 42
41 void Scheduler::SetCanDraw(bool can_draw) { 43 void Scheduler::SetCanDraw(bool can_draw) {
42 state_machine_.SetCanDraw(can_draw); 44 state_machine_.SetCanDraw(can_draw);
43 ProcessScheduledActions(); 45 ProcessScheduledActions();
44 } 46 }
45 47
46 void Scheduler::SetHasPendingTree(bool has_pending_tree) { 48 void Scheduler::NotifyReadyToActivate() {
47 state_machine_.SetHasPendingTree(has_pending_tree); 49 state_machine_.NotifyReadyToActivate();
48 ProcessScheduledActions(); 50 ProcessScheduledActions();
49 } 51 }
50 52
53 void Scheduler::SetHasTrees(bool has_pending_tree, bool active_tree_is_null) {
54 state_machine_.SetHasTrees(has_pending_tree, active_tree_is_null);
55 ProcessScheduledActions();
56
57 if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly())
58 PostBeginFrameDeadline(base::TimeTicks());
59 }
60
51 void Scheduler::SetNeedsCommit() { 61 void Scheduler::SetNeedsCommit() {
52 state_machine_.SetNeedsCommit(); 62 state_machine_.SetNeedsCommit();
53 ProcessScheduledActions(); 63 ProcessScheduledActions();
54 } 64 }
55 65
56 void Scheduler::SetNeedsForcedCommit() { 66 void Scheduler::SetNeedsForcedCommitForReadback() {
57 state_machine_.SetNeedsCommit(); 67 state_machine_.SetNeedsCommit();
58 state_machine_.SetNeedsForcedCommit(); 68 state_machine_.SetNeedsForcedCommitForReadback();
59 ProcessScheduledActions(); 69 ProcessScheduledActions();
60 } 70 }
61 71
62 void Scheduler::SetNeedsRedraw() { 72 void Scheduler::SetNeedsRedraw() {
63 state_machine_.SetNeedsRedraw(); 73 state_machine_.SetNeedsRedraw();
64 ProcessScheduledActions(); 74 ProcessScheduledActions();
65 } 75 }
66 76
67 void Scheduler::DidSwapUseIncompleteTile() { 77 void Scheduler::DidSwapUseIncompleteTile() {
68 state_machine_.DidSwapUseIncompleteTile(); 78 state_machine_.DidSwapUseIncompleteTile();
69 ProcessScheduledActions(); 79 ProcessScheduledActions();
70 } 80 }
71 81
72 void Scheduler::SetNeedsForcedRedraw() {
73 state_machine_.SetNeedsForcedRedraw();
74 ProcessScheduledActions();
75 }
76
77 void Scheduler::SetMainThreadNeedsLayerTextures() { 82 void Scheduler::SetMainThreadNeedsLayerTextures() {
78 state_machine_.SetMainThreadNeedsLayerTextures(); 83 state_machine_.SetMainThreadNeedsLayerTextures();
79 ProcessScheduledActions(); 84 ProcessScheduledActions();
80 } 85 }
81 86
82 void Scheduler::FinishCommit() { 87 void Scheduler::FinishCommit() {
83 TRACE_EVENT0("cc", "Scheduler::FinishCommit"); 88 TRACE_EVENT0("cc", "Scheduler::FinishCommit");
84 state_machine_.FinishCommit(); 89 state_machine_.FinishCommit();
85 ProcessScheduledActions(); 90 ProcessScheduledActions();
91
92 if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly())
93 PostBeginFrameDeadline(base::TimeTicks());
86 } 94 }
87 95
88 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { 96 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) {
89 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread"); 97 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread");
90 state_machine_.BeginFrameAbortedByMainThread(did_handle); 98 state_machine_.BeginFrameAbortedByMainThread(did_handle);
91 ProcessScheduledActions(); 99 ProcessScheduledActions();
92 } 100 }
93 101
94 void Scheduler::DidLoseOutputSurface() { 102 void Scheduler::DidLoseOutputSurface() {
95 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); 103 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
104 begin_frame_deadline_closure_.Cancel();
105 has_pending_begin_frame_ = false;
96 state_machine_.DidLoseOutputSurface(); 106 state_machine_.DidLoseOutputSurface();
97 ProcessScheduledActions(); 107 ProcessScheduledActions();
98 } 108 }
99 109
100 void Scheduler::DidCreateAndInitializeOutputSurface() { 110 void Scheduler::DidCreateAndInitializeOutputSurface() {
101 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); 111 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
102 state_machine_.DidCreateAndInitializeOutputSurface(); 112 state_machine_.DidCreateAndInitializeOutputSurface();
113 begin_frame_deadline_closure_.Cancel();
103 has_pending_begin_frame_ = false; 114 has_pending_begin_frame_ = false;
104 last_set_needs_begin_frame_ = false; 115 last_set_needs_begin_frame_ = false;
105 safe_to_expect_begin_frame_ = false; 116 safe_to_expect_begin_frame_ =
117 !settings_.use_begin_frame_workaround_for_crbug_249806;
106 ProcessScheduledActions(); 118 ProcessScheduledActions();
107 } 119 }
108 120
109 base::TimeTicks Scheduler::AnticipatedDrawTime() { 121 base::TimeTicks Scheduler::AnticipatedDrawTime() {
110 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); 122 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime");
111 123
112 if (!last_set_needs_begin_frame_ || 124 if (!last_set_needs_begin_frame_ ||
113 last_begin_frame_args_.interval <= base::TimeDelta()) 125 last_begin_frame_args_.interval <= base::TimeDelta())
114 return base::TimeTicks(); 126 return base::TimeTicks();
115 127
116 // TODO(brianderson): Express this in terms of the deadline.
117 base::TimeTicks now = base::TimeTicks::Now(); 128 base::TimeTicks now = base::TimeTicks::Now();
118 int64 intervals = 1 + ((now - last_begin_frame_args_.frame_time) / 129 base::TimeTicks timebase = std::max(last_begin_frame_args_.frame_time,
119 last_begin_frame_args_.interval); 130 last_begin_frame_args_.deadline);
120 return last_begin_frame_args_.frame_time + 131 int64 intervals = 1 + ((now - timebase) / last_begin_frame_args_.interval);
121 (last_begin_frame_args_.interval * intervals); 132 return timebase + (last_begin_frame_args_.interval * intervals);
122 } 133 }
123 134
124 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { 135 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() {
125 return last_begin_frame_args_.frame_time; 136 return last_begin_frame_args_.frame_time;
126 } 137 }
127 138
128 void Scheduler::SetupNextBeginFrameIfNeeded() { 139 void Scheduler::SetupNextBeginFrameIfNeeded() {
129 bool needs_begin_frame_to_draw = 140 bool needs_begin_frame_to_draw =
130 state_machine_.BeginFrameNeededToDrawByImplThread(); 141 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 = 142 bool proactive_begin_frame_wanted =
134 state_machine_.ProactiveBeginFrameWantedByImplThread() && 143 state_machine_.BeginFrameProactivelyNeededByImplThread();
135 !settings_.using_synchronous_renderer_compositor && 144
136 settings_.throttle_frame_production; 145 // We want to avoid proactive begin frames with the synchronous
137 bool needs_begin_frame = needs_begin_frame_to_draw || 146 // compositor because every SetNeedsBeginFrame will force a redraw.
138 proactive_begin_frame_wanted; 147 bool needs_begin_frame =
139 bool immediate_disables_needed = 148 needs_begin_frame_to_draw || proactive_begin_frame_wanted;
140 settings_.using_synchronous_renderer_compositor; 149
150 bool should_call_set_needs_begin_frame =
151 // The synchronous renderer compositor needs immediate enables/disables.
152 (settings_.using_synchronous_renderer_compositor &&
153 needs_begin_frame != last_set_needs_begin_frame_) ||
154 // Always request the BeginFrame immediately if it wasn't needed before.
155 (needs_begin_frame && !last_set_needs_begin_frame_) ||
156 // Only disable the BeginFrame after a BeginFrame where we didn't swap.
157 (!needs_begin_frame && last_set_needs_begin_frame_ &&
158 has_pending_begin_frame_ && !state_machine_.InsideBeginFrame()) ||
159 // We did not draw and swap this BeginFrame,
160 // so we need to explicitly request another BeginFrame.
161 (needs_begin_frame && has_pending_begin_frame_ &&
162 !state_machine_.InsideBeginFrame());
141 163
142 if (needs_begin_frame_to_draw) 164 if (needs_begin_frame_to_draw)
143 safe_to_expect_begin_frame_ = true; 165 safe_to_expect_begin_frame_ = true;
144 166
145 // Determine if we need BeginFrame notifications. 167 if (should_call_set_needs_begin_frame) {
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; 168 has_pending_begin_frame_ = false;
154 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); 169 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame);
155 if (safe_to_expect_begin_frame_) 170 if (safe_to_expect_begin_frame_)
156 last_set_needs_begin_frame_ = needs_begin_frame; 171 last_set_needs_begin_frame_ = needs_begin_frame;
157 } 172 }
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 return;
165 }
166 } 173 }
167 174
168 void Scheduler::BeginFrame(const BeginFrameArgs& args) { 175 void Scheduler::BeginFrame(const BeginFrameArgs& args) {
169 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); 176 TRACE_EVENT0("cc", "Scheduler::BeginFrame");
170 DCHECK(!has_pending_begin_frame_); 177 DCHECK(!has_pending_begin_frame_);
171 has_pending_begin_frame_ = true; 178 has_pending_begin_frame_ = true;
172 safe_to_expect_begin_frame_ = true; 179 safe_to_expect_begin_frame_ = true;
173 last_begin_frame_args_ = args; 180 last_begin_frame_args_ = args;
174 state_machine_.DidEnterBeginFrame(args); 181 last_begin_frame_args_.deadline -= client_->DrawDurationEstimate();
182 state_machine_.OnBeginFrame(last_begin_frame_args_);
175 ProcessScheduledActions(); 183 ProcessScheduledActions();
176 state_machine_.DidLeaveBeginFrame(); 184
185 if (settings_.using_synchronous_renderer_compositor) {
186 // The synchronous renderer compositor has to make it's GL calls
187 // within this call to BeginFrame.
188 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
189 // so the sychronous renderer compoistor can take advantage of splitting
190 // up the BeginFrame and deadline as well.
191 OnBeginFrameDeadline();
192 } else if (!settings_.deadline_scheduling_enabled) {
193 // We emulate the old non-deadline scheduler here by posting the
brianderson 2013/08/20 02:03:01 I got rid of the AdjustDeadline function that had
194 // deadline task without any delay.
195 PostBeginFrameDeadline(base::TimeTicks());
196 } else if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) {
197 // We are ready to draw a new active tree immediately.
198 PostBeginFrameDeadline(base::TimeTicks());
199 } else if (state_machine_.needs_redraw()) {
200 // We have an animation or fast input path on the impl thread that wants
201 // to draw, so don't wait too long for a new active tree.
202 PostBeginFrameDeadline(last_begin_frame_args_.deadline);
203 } else {
204 // The impl thread doesn't have anything it wants to draw and we are just
205 // waiting for a new active tree, so post the deadline for the next
206 // expected BeginFrame start.
207 // TODO(brianderson): Handle long deadlines (that are past the next frame's
208 // frame time) properly instead of using this hack.
209 PostBeginFrameDeadline(last_begin_frame_args_.frame_time +
210 last_begin_frame_args_.interval);
211 }
212 }
213
214 void Scheduler::PostBeginFrameDeadline(base::TimeTicks deadline) {
215 begin_frame_deadline_closure_.Cancel();
216 begin_frame_deadline_closure_.Reset(
217 base::Bind(&Scheduler::OnBeginFrameDeadline, weak_factory_.GetWeakPtr()));
218 client_->PostBeginFrameDeadline(begin_frame_deadline_closure_.callback(),
219 deadline);
220 }
221
222 void Scheduler::OnBeginFrameDeadline() {
223 TRACE_EVENT0("cc", "Scheduler::OnBeginFrameDeadline");
224 begin_frame_deadline_closure_.Cancel();
225 state_machine_.OnBeginFrameDeadline();
226 ProcessScheduledActions();
227 client_->DidBeginFrameDeadlineOnImplThread();
177 } 228 }
178 229
179 void Scheduler::DrawAndSwapIfPossible() { 230 void Scheduler::DrawAndSwapIfPossible() {
180 ScheduledActionDrawAndSwapResult result = 231 DrawSwapReadbackResult result =
181 client_->ScheduledActionDrawAndSwapIfPossible(); 232 client_->ScheduledActionDrawAndSwapIfPossible();
182 state_machine_.DidDrawIfPossibleCompleted(result.did_draw); 233 state_machine_.DidDrawIfPossibleCompleted(result.did_draw);
183 if (result.did_swap) 234 if (result.did_swap)
184 has_pending_begin_frame_ = false; 235 has_pending_begin_frame_ = false;
185 } 236 }
186 237
187 void Scheduler::DrawAndSwapForced() { 238 void Scheduler::DrawAndSwapForced() {
188 ScheduledActionDrawAndSwapResult result = 239 DrawSwapReadbackResult result = client_->ScheduledActionDrawAndSwapForced();
189 client_->ScheduledActionDrawAndSwapForced();
190 if (result.did_swap) 240 if (result.did_swap)
191 has_pending_begin_frame_ = false; 241 has_pending_begin_frame_ = false;
192 } 242 }
193 243
194 void Scheduler::ProcessScheduledActions() { 244 void Scheduler::ProcessScheduledActions() {
195 // We do not allow ProcessScheduledActions to be recursive. 245 // We do not allow ProcessScheduledActions to be recursive.
196 // The top-level call will iteratively execute the next action for us anyway. 246 // The top-level call will iteratively execute the next action for us anyway.
197 if (inside_process_scheduled_actions_) 247 if (inside_process_scheduled_actions_)
198 return; 248 return;
199 249
200 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true); 250 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
201 251
202 SchedulerStateMachine::Action action = state_machine_.NextAction(); 252 SchedulerStateMachine::Action action;
203 while (action != SchedulerStateMachine::ACTION_NONE) { 253 do {
254 action = state_machine_.NextAction();
255 TRACE_EVENT2("cc",
256 "SchedulerStateMachine",
257 "action",
258 action,
259 "state",
260 state_machine_.ToString());
204 state_machine_.UpdateState(action); 261 state_machine_.UpdateState(action);
205 switch (action) { 262 switch (action) {
206 case SchedulerStateMachine::ACTION_NONE: 263 case SchedulerStateMachine::ACTION_NONE:
207 break; 264 break;
208 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: 265 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD:
209 client_->ScheduledActionSendBeginFrameToMainThread(); 266 client_->ScheduledActionSendBeginFrameToMainThread();
210 break; 267 break;
211 case SchedulerStateMachine::ACTION_COMMIT: 268 case SchedulerStateMachine::ACTION_COMMIT:
212 client_->ScheduledActionCommit(); 269 client_->ScheduledActionCommit();
213 break; 270 break;
214 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: 271 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
215 client_->ScheduledActionUpdateVisibleTiles(); 272 client_->ScheduledActionUpdateVisibleTiles();
216 break; 273 break;
217 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED: 274 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE:
218 client_->ScheduledActionActivatePendingTreeIfNeeded(); 275 client_->ScheduledActionActivatePendingTree();
219 break; 276 break;
220 case SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE: 277 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
221 DrawAndSwapIfPossible(); 278 DrawAndSwapIfPossible();
222 break; 279 break;
223 case SchedulerStateMachine::ACTION_DRAW_FORCED: 280 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
224 DrawAndSwapForced(); 281 DrawAndSwapForced();
225 break; 282 break;
283 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
284 // No action is actually performed, but this allows the state machine to
285 // advance out of its waiting to draw state without actually drawing.
286 break;
287 case SchedulerStateMachine::ACTION_DRAW_AND_READBACK:
288 client_->ScheduledActionDrawAndReadback();
289 break;
226 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: 290 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
227 client_->ScheduledActionBeginOutputSurfaceCreation(); 291 client_->ScheduledActionBeginOutputSurfaceCreation();
228 break; 292 break;
229 case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD: 293 case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
230 client_->ScheduledActionAcquireLayerTexturesForMainThread(); 294 client_->ScheduledActionAcquireLayerTexturesForMainThread();
231 break; 295 break;
232 } 296 }
233 action = state_machine_.NextAction(); 297 } while (action != SchedulerStateMachine::ACTION_NONE);
234 }
235 298
299 state_machine_.AdvanceBeginFrameStateWhenNoActionsRemain();
236 SetupNextBeginFrameIfNeeded(); 300 SetupNextBeginFrameIfNeeded();
237 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); 301 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
238 } 302 }
239 303
240 bool Scheduler::WillDrawIfNeeded() const { 304 bool Scheduler::WillDrawIfNeeded() const {
241 return !state_machine_.DrawSuspendedUntilCommit(); 305 return !state_machine_.DrawSuspendedUntilCommit();
242 } 306 }
243 307
244 } // namespace cc 308 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698