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

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

Issue 23796002: cc: Implement deadine scheduling disabled by default (Closed) Base URL: http://git.chromium.org/chromium/src.git@schedReadback4
Patch Set: address enne's comments Created 7 years, 3 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 #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 has_pending_begin_frame_(false), 21 begin_frame_did_not_swap_count_(0),
21 state_machine_(scheduler_settings), 22 state_machine_(scheduler_settings),
22 inside_process_scheduled_actions_(false) { 23 inside_process_scheduled_actions_(false) {
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 10 matching lines...) Expand all
71 76
72 void Scheduler::SetMainThreadNeedsLayerTextures() { 77 void Scheduler::SetMainThreadNeedsLayerTextures() {
73 state_machine_.SetMainThreadNeedsLayerTextures(); 78 state_machine_.SetMainThreadNeedsLayerTextures();
74 ProcessScheduledActions(); 79 ProcessScheduledActions();
75 } 80 }
76 81
77 void Scheduler::FinishCommit() { 82 void Scheduler::FinishCommit() {
78 TRACE_EVENT0("cc", "Scheduler::FinishCommit"); 83 TRACE_EVENT0("cc", "Scheduler::FinishCommit");
79 state_machine_.FinishCommit(); 84 state_machine_.FinishCommit();
80 ProcessScheduledActions(); 85 ProcessScheduledActions();
86
87 if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly())
88 PostBeginFrameDeadline(base::TimeTicks());
81 } 89 }
82 90
83 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { 91 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) {
84 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread"); 92 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread");
85 state_machine_.BeginFrameAbortedByMainThread(did_handle); 93 state_machine_.BeginFrameAbortedByMainThread(did_handle);
86 ProcessScheduledActions(); 94 ProcessScheduledActions();
87 } 95 }
88 96
89 void Scheduler::DidLoseOutputSurface() { 97 void Scheduler::DidLoseOutputSurface() {
90 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); 98 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
99 last_set_needs_begin_frame_ = false;
100 begin_frame_did_not_swap_count_ = 0;
101 begin_frame_deadline_closure_.Cancel();
91 state_machine_.DidLoseOutputSurface(); 102 state_machine_.DidLoseOutputSurface();
92 ProcessScheduledActions(); 103 ProcessScheduledActions();
93 } 104 }
94 105
95 void Scheduler::DidCreateAndInitializeOutputSurface() { 106 void Scheduler::DidCreateAndInitializeOutputSurface() {
96 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); 107 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
108 DCHECK(!last_set_needs_begin_frame_);
109 DCHECK_EQ(begin_frame_did_not_swap_count_, 0);
110 DCHECK(begin_frame_deadline_closure_.IsCancelled());
97 state_machine_.DidCreateAndInitializeOutputSurface(); 111 state_machine_.DidCreateAndInitializeOutputSurface();
98 has_pending_begin_frame_ = false;
99 last_set_needs_begin_frame_ = false;
100 ProcessScheduledActions(); 112 ProcessScheduledActions();
101 } 113 }
102 114
103 base::TimeTicks Scheduler::AnticipatedDrawTime() { 115 base::TimeTicks Scheduler::AnticipatedDrawTime() {
104 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); 116 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime");
105 117
106 if (!last_set_needs_begin_frame_ || 118 if (!last_set_needs_begin_frame_ ||
107 last_begin_frame_args_.interval <= base::TimeDelta()) 119 last_begin_frame_args_.interval <= base::TimeDelta())
108 return base::TimeTicks(); 120 return base::TimeTicks();
109 121
110 // TODO(brianderson): Express this in terms of the deadline.
111 base::TimeTicks now = base::TimeTicks::Now(); 122 base::TimeTicks now = base::TimeTicks::Now();
112 int64 intervals = 1 + ((now - last_begin_frame_args_.frame_time) / 123 base::TimeTicks timebase = std::max(last_begin_frame_args_.frame_time,
113 last_begin_frame_args_.interval); 124 last_begin_frame_args_.deadline);
114 return last_begin_frame_args_.frame_time + 125 int64 intervals = 1 + ((now - timebase) / last_begin_frame_args_.interval);
115 (last_begin_frame_args_.interval * intervals); 126 return timebase + (last_begin_frame_args_.interval * intervals);
116 } 127 }
117 128
118 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { 129 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() {
119 return last_begin_frame_args_.frame_time; 130 return last_begin_frame_args_.frame_time;
120 } 131 }
121 132
122 void Scheduler::SetupNextBeginFrameIfNeeded() { 133 void Scheduler::SetupNextBeginFrameIfNeeded() {
123 bool needs_begin_frame_to_draw = 134 bool needs_begin_frame =
124 state_machine_.BeginFrameNeededToDrawByImplThread(); 135 state_machine_.BeginFrameNeededByImplThread();
125 // We want to avoid proactive begin frames with the synchronous compositor
126 // because every SetNeedsBeginFrame will force a redraw.
127 bool proactive_begin_frame_wanted =
128 state_machine_.ProactiveBeginFrameWantedByImplThread() &&
129 !settings_.using_synchronous_renderer_compositor &&
130 settings_.throttle_frame_production;
131 bool needs_begin_frame = needs_begin_frame_to_draw ||
132 proactive_begin_frame_wanted;
133 bool immediate_disables_needed =
134 settings_.using_synchronous_renderer_compositor;
135 136
136 // Determine if we need BeginFrame notifications. 137 bool should_call_set_needs_begin_frame =
137 // If we do, always request the BeginFrame immediately. 138 // Always request the BeginFrame immediately if it wasn't needed before.
138 // If not, only disable on the next BeginFrame to avoid unnecessary toggles. 139 (needs_begin_frame && !last_set_needs_begin_frame_) ||
139 // The synchronous renderer compositor requires immediate disables though. 140 // We always need to explicitly request our next BeginFrame.
140 if ((needs_begin_frame || 141 state_machine_.begin_frame_state() ==
141 state_machine_.inside_begin_frame() || 142 SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE;
142 immediate_disables_needed) && 143
143 (needs_begin_frame != last_set_needs_begin_frame_)) { 144 // Only disable the BeginFrame after a BeginFrame where we didn't swap,
enne (OOO) 2013/09/12 21:56:22 Can you phrase this in the positive to match the f
brianderson 2013/09/12 22:42:54 I will change the comment. It's trying to keep ne
144 has_pending_begin_frame_ = false; 145 // except for the synchronous renderer compositor, which wants immediate
146 // enables/disables to avoid unnecessary draws.
147 int negative_edge_glitch_threshold =
148 settings_.using_synchronous_renderer_compositor ? 0 : 1;
enne (OOO) 2013/09/12 21:56:22 This seems like it should really just be if (!sett
149 if (begin_frame_did_not_swap_count_ < negative_edge_glitch_threshold &&
enne (OOO) 2013/09/12 21:56:22 bikeshed: Could you not put 'not' in a variable na
brianderson 2013/09/12 22:42:54 That prevents us from using a larger threshold, bu
150 state_machine_.begin_frame_state() ==
151 SchedulerStateMachine::BEGIN_FRAME_STATE_INSIDE_DEADLINE) {
152 needs_begin_frame = true;
153 }
154
155 if (should_call_set_needs_begin_frame) {
145 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); 156 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame);
146 last_set_needs_begin_frame_ = needs_begin_frame; 157 last_set_needs_begin_frame_ = needs_begin_frame;
147 } 158 }
148 159
149 // Request another BeginFrame if we haven't drawn for now until we have
150 // deadlines implemented.
151 if (state_machine_.inside_begin_frame() && has_pending_begin_frame_) {
152 has_pending_begin_frame_ = false;
153 client_->SetNeedsBeginFrameOnImplThread(true);
154 }
155
156 // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive 160 // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive
157 // BeginFrame but aren't requesting one. 161 // BeginFrame but aren't requesting one.
158 if (!needs_begin_frame && 162 if (!last_set_needs_begin_frame_ &&
159 state_machine_.ProactiveBeginFrameWantedByImplThread()) { 163 state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
160 if (poll_for_draw_triggers_closure_.IsCancelled()) { 164 if (poll_for_draw_triggers_closure_.IsCancelled()) {
161 poll_for_draw_triggers_closure_.Reset( 165 poll_for_draw_triggers_closure_.Reset(
162 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers, 166 base::Bind(&Scheduler::PollForAnticipatedDrawTriggers,
163 weak_factory_.GetWeakPtr())); 167 weak_factory_.GetWeakPtr()));
164 base::MessageLoop::current()->PostDelayedTask( 168 base::MessageLoop::current()->PostDelayedTask(
165 FROM_HERE, 169 FROM_HERE,
166 poll_for_draw_triggers_closure_.callback(), 170 poll_for_draw_triggers_closure_.callback(),
167 last_begin_frame_args_.interval); 171 last_begin_frame_args_.interval);
168 } 172 }
169 } else { 173 } else {
170 poll_for_draw_triggers_closure_.Cancel(); 174 poll_for_draw_triggers_closure_.Cancel();
171 } 175 }
172 } 176 }
173 177
174 void Scheduler::BeginFrame(const BeginFrameArgs& args) { 178 void Scheduler::BeginFrame(const BeginFrameArgs& args) {
175 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); 179 TRACE_EVENT0("cc", "Scheduler::BeginFrame");
176 DCHECK(!has_pending_begin_frame_); 180 begin_frame_did_not_swap_count_++;
177 has_pending_begin_frame_ = true;
178 last_begin_frame_args_ = args; 181 last_begin_frame_args_ = args;
179 state_machine_.DidEnterBeginFrame(args); 182 last_begin_frame_args_.deadline -= client_->DrawDurationEstimate();
183 state_machine_.OnBeginFrame(last_begin_frame_args_);
180 ProcessScheduledActions(); 184 ProcessScheduledActions();
181 state_machine_.DidLeaveBeginFrame(); 185 state_machine_.OnBeginFrameDeadlinePending();
186
187 if (settings_.using_synchronous_renderer_compositor) {
188 // The synchronous renderer compositor has to make its GL calls
189 // within this call to BeginFrame.
190 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
191 // so the sychronous renderer compoistor can take advantage of splitting
192 // up the BeginFrame and deadline as well.
193 OnBeginFrameDeadline();
194 } else if (!settings_.deadline_scheduling_enabled) {
195 // We emulate the old non-deadline scheduler here by posting the
196 // deadline task without any delay.
197 PostBeginFrameDeadline(base::TimeTicks());
198 } else if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) {
199 // We are ready to draw a new active tree immediately.
200 PostBeginFrameDeadline(base::TimeTicks());
201 } else if (state_machine_.needs_redraw()) {
202 // We have an animation or fast input path on the impl thread that wants
203 // to draw, so don't wait too long for a new active tree.
204 PostBeginFrameDeadline(last_begin_frame_args_.deadline);
205 } else {
206 // The impl thread doesn't have anything it wants to draw and we are just
207 // waiting for a new active tree, so post the deadline for the next
208 // expected BeginFrame start. This allows us to draw immediately when
209 // there is a new active tree, instead of waiting for the next BeginFrame.
210 // TODO(brianderson): Handle long deadlines (that are past the next frame's
211 // frame time) properly instead of using this hack.
212 PostBeginFrameDeadline(last_begin_frame_args_.frame_time +
213 last_begin_frame_args_.interval);
214 }
215 }
216
217 void Scheduler::PostBeginFrameDeadline(base::TimeTicks deadline) {
218 begin_frame_deadline_closure_.Cancel();
219 begin_frame_deadline_closure_.Reset(
220 base::Bind(&Scheduler::OnBeginFrameDeadline, weak_factory_.GetWeakPtr()));
221 client_->PostBeginFrameDeadline(begin_frame_deadline_closure_.callback(),
222 deadline);
223 }
224
225 void Scheduler::OnBeginFrameDeadline() {
226 TRACE_EVENT0("cc", "Scheduler::OnBeginFrameDeadline");
227 begin_frame_deadline_closure_.Cancel();
228 state_machine_.OnBeginFrameDeadline();
229 ProcessScheduledActions();
230 // We only transition out of BEGIN_FRAME_STATE_INSIDE_DEADLINE when all
231 // actions that occur back-to-back in response to entering
232 // BEGIN_FRAME_STATE_INSIDE_DEADLINE have completed. This is important
233 // because sending the BeginFrame to the main thread will not occur if
234 // we transition to BEGIN_FRAME_STATE_IDLE too early.
235 state_machine_.OnBeginFrameIdle();
236 client_->DidBeginFrameDeadlineOnImplThread();
182 } 237 }
183 238
184 void Scheduler::PollForAnticipatedDrawTriggers() { 239 void Scheduler::PollForAnticipatedDrawTriggers() {
185 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); 240 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
186 state_machine_.PollForAnticipatedDrawTriggers(); 241 state_machine_.PollForAnticipatedDrawTriggers();
187 ProcessScheduledActions(); 242 ProcessScheduledActions();
188 } 243 }
189 244
190 void Scheduler::DrawAndSwapIfPossible() { 245 void Scheduler::DrawAndSwapIfPossible() {
191 DrawSwapReadbackResult result = 246 DrawSwapReadbackResult result =
192 client_->ScheduledActionDrawAndSwapIfPossible(); 247 client_->ScheduledActionDrawAndSwapIfPossible();
193 state_machine_.DidDrawIfPossibleCompleted(result.did_draw); 248 state_machine_.DidDrawIfPossibleCompleted(result.did_draw);
249 begin_frame_did_not_swap_count_ = 0;
194 } 250 }
195 251
196 void Scheduler::DrawAndSwapForced() { 252 void Scheduler::DrawAndSwapForced() {
197 client_->ScheduledActionDrawAndSwapForced(); 253 client_->ScheduledActionDrawAndSwapForced();
254 begin_frame_did_not_swap_count_ = 0;
198 } 255 }
199 256
200 void Scheduler::DrawAndReadback() { 257 void Scheduler::DrawAndReadback() {
201 DrawSwapReadbackResult result = client_->ScheduledActionDrawAndReadback(); 258 DrawSwapReadbackResult result = client_->ScheduledActionDrawAndReadback();
202 DCHECK(!result.did_swap); 259 DCHECK(!result.did_swap);
203 } 260 }
204 261
205 void Scheduler::ProcessScheduledActions() { 262 void Scheduler::ProcessScheduledActions() {
206 // We do not allow ProcessScheduledActions to be recursive. 263 // We do not allow ProcessScheduledActions to be recursive.
207 // The top-level call will iteratively execute the next action for us anyway. 264 // The top-level call will iteratively execute the next action for us anyway.
(...skipping 17 matching lines...) Expand all
225 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: 282 case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD:
226 client_->ScheduledActionSendBeginFrameToMainThread(); 283 client_->ScheduledActionSendBeginFrameToMainThread();
227 break; 284 break;
228 case SchedulerStateMachine::ACTION_COMMIT: 285 case SchedulerStateMachine::ACTION_COMMIT:
229 client_->ScheduledActionCommit(); 286 client_->ScheduledActionCommit();
230 break; 287 break;
231 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: 288 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
232 client_->ScheduledActionUpdateVisibleTiles(); 289 client_->ScheduledActionUpdateVisibleTiles();
233 break; 290 break;
234 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: 291 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE:
235 client_->ScheduledActionActivatePendingTree(); 292 ActivatePendingTree();
236 break; 293 break;
237 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: 294 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
238 DrawAndSwapIfPossible(); 295 DrawAndSwapIfPossible();
239 break; 296 break;
240 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: 297 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
241 DrawAndSwapForced(); 298 DrawAndSwapForced();
242 break; 299 break;
243 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: 300 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
244 // 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
245 // advance out of its waiting to draw state without actually drawing. 302 // advance out of its waiting to draw state without actually drawing.
(...skipping 12 matching lines...) Expand all
258 315
259 SetupNextBeginFrameIfNeeded(); 316 SetupNextBeginFrameIfNeeded();
260 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); 317 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
261 } 318 }
262 319
263 bool Scheduler::WillDrawIfNeeded() const { 320 bool Scheduler::WillDrawIfNeeded() const {
264 return !state_machine_.PendingDrawsShouldBeAborted(); 321 return !state_machine_.PendingDrawsShouldBeAborted();
265 } 322 }
266 323
267 } // namespace cc 324 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698