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 has_pending_begin_frame_(false), | 21 has_pending_begin_frame_(false), |
21 safe_to_expect_begin_frame_(false), | 22 safe_to_expect_begin_frame_( |
| 23 !scheduler_settings.use_begin_frame_workaround_for_crbug_249806), |
22 state_machine_(scheduler_settings), | 24 state_machine_(scheduler_settings), |
23 inside_process_scheduled_actions_(false) { | 25 inside_process_scheduled_actions_(false) { |
24 DCHECK(client_); | 26 DCHECK(client_); |
25 DCHECK(!state_machine_.BeginFrameNeededToDrawByImplThread()); | 27 DCHECK(!state_machine_.BeginFrameNeededByImplThread()); |
26 } | 28 } |
27 | 29 |
28 Scheduler::~Scheduler() { | 30 Scheduler::~Scheduler() { |
29 client_->SetNeedsBeginFrameOnImplThread(false); | 31 client_->SetNeedsBeginFrameOnImplThread(false); |
30 } | 32 } |
31 | 33 |
32 void Scheduler::SetCanStart() { | 34 void Scheduler::SetCanStart() { |
33 state_machine_.SetCanStart(); | 35 state_machine_.SetCanStart(); |
34 ProcessScheduledActions(); | 36 ProcessScheduledActions(); |
35 } | 37 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
72 | 74 |
73 void Scheduler::SetMainThreadNeedsLayerTextures() { | 75 void Scheduler::SetMainThreadNeedsLayerTextures() { |
74 state_machine_.SetMainThreadNeedsLayerTextures(); | 76 state_machine_.SetMainThreadNeedsLayerTextures(); |
75 ProcessScheduledActions(); | 77 ProcessScheduledActions(); |
76 } | 78 } |
77 | 79 |
78 void Scheduler::FinishCommit() { | 80 void Scheduler::FinishCommit() { |
79 TRACE_EVENT0("cc", "Scheduler::FinishCommit"); | 81 TRACE_EVENT0("cc", "Scheduler::FinishCommit"); |
80 state_machine_.FinishCommit(); | 82 state_machine_.FinishCommit(); |
81 ProcessScheduledActions(); | 83 ProcessScheduledActions(); |
| 84 |
| 85 if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) |
| 86 PostBeginFrameDeadline(base::TimeTicks()); |
82 } | 87 } |
83 | 88 |
84 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { | 89 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) { |
85 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread"); | 90 TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread"); |
86 state_machine_.BeginFrameAbortedByMainThread(did_handle); | 91 state_machine_.BeginFrameAbortedByMainThread(did_handle); |
87 ProcessScheduledActions(); | 92 ProcessScheduledActions(); |
88 } | 93 } |
89 | 94 |
90 void Scheduler::DidLoseOutputSurface() { | 95 void Scheduler::DidLoseOutputSurface() { |
91 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); | 96 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); |
| 97 begin_frame_deadline_closure_.Cancel(); |
| 98 has_pending_begin_frame_ = false; |
92 state_machine_.DidLoseOutputSurface(); | 99 state_machine_.DidLoseOutputSurface(); |
93 ProcessScheduledActions(); | 100 ProcessScheduledActions(); |
94 } | 101 } |
95 | 102 |
96 void Scheduler::DidCreateAndInitializeOutputSurface() { | 103 void Scheduler::DidCreateAndInitializeOutputSurface() { |
97 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); | 104 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); |
98 state_machine_.DidCreateAndInitializeOutputSurface(); | 105 state_machine_.DidCreateAndInitializeOutputSurface(); |
| 106 begin_frame_deadline_closure_.Cancel(); |
99 has_pending_begin_frame_ = false; | 107 has_pending_begin_frame_ = false; |
100 last_set_needs_begin_frame_ = false; | 108 last_set_needs_begin_frame_ = false; |
101 safe_to_expect_begin_frame_ = false; | 109 safe_to_expect_begin_frame_ = |
| 110 !settings_.use_begin_frame_workaround_for_crbug_249806; |
102 ProcessScheduledActions(); | 111 ProcessScheduledActions(); |
103 } | 112 } |
104 | 113 |
105 base::TimeTicks Scheduler::AnticipatedDrawTime() { | 114 base::TimeTicks Scheduler::AnticipatedDrawTime() { |
106 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); | 115 TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime"); |
107 | 116 |
108 if (!last_set_needs_begin_frame_ || | 117 if (!last_set_needs_begin_frame_ || |
109 last_begin_frame_args_.interval <= base::TimeDelta()) | 118 last_begin_frame_args_.interval <= base::TimeDelta()) |
110 return base::TimeTicks(); | 119 return base::TimeTicks(); |
111 | 120 |
112 // TODO(brianderson): Express this in terms of the deadline. | |
113 base::TimeTicks now = base::TimeTicks::Now(); | 121 base::TimeTicks now = base::TimeTicks::Now(); |
114 int64 intervals = 1 + ((now - last_begin_frame_args_.frame_time) / | 122 base::TimeTicks timebase = std::max(last_begin_frame_args_.frame_time, |
115 last_begin_frame_args_.interval); | 123 last_begin_frame_args_.deadline); |
116 return last_begin_frame_args_.frame_time + | 124 int64 intervals = 1 + ((now - timebase) / last_begin_frame_args_.interval); |
117 (last_begin_frame_args_.interval * intervals); | 125 return timebase + (last_begin_frame_args_.interval * intervals); |
118 } | 126 } |
119 | 127 |
120 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { | 128 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() { |
121 return last_begin_frame_args_.frame_time; | 129 return last_begin_frame_args_.frame_time; |
122 } | 130 } |
123 | 131 |
124 void Scheduler::SetupNextBeginFrameIfNeeded() { | 132 void Scheduler::SetupNextBeginFrameIfNeeded() { |
125 bool needs_begin_frame_to_draw = | 133 bool needs_begin_frame_to_draw = |
126 state_machine_.BeginFrameNeededToDrawByImplThread(); | 134 state_machine_.BeginFrameNeededToDrawByImplThread(); |
127 // We want to avoid proactive begin frames with the synchronous compositor | |
128 // because every SetNeedsBeginFrame will force a redraw. | |
129 bool proactive_begin_frame_wanted = | 135 bool proactive_begin_frame_wanted = |
130 state_machine_.ProactiveBeginFrameWantedByImplThread() && | 136 state_machine_.ProactiveBeginFrameWantedByImplThread(); |
131 !settings_.using_synchronous_renderer_compositor && | 137 |
132 settings_.throttle_frame_production; | 138 // We want to avoid proactive begin frames with the synchronous |
133 bool needs_begin_frame = needs_begin_frame_to_draw || | 139 // compositor because every SetNeedsBeginFrame will force a redraw. |
134 proactive_begin_frame_wanted; | 140 bool needs_begin_frame = |
135 bool immediate_disables_needed = | 141 needs_begin_frame_to_draw || proactive_begin_frame_wanted; |
136 settings_.using_synchronous_renderer_compositor; | 142 |
| 143 bool should_call_set_needs_begin_frame = |
| 144 // The synchronous renderer compositor needs immediate enables/disables. |
| 145 (settings_.using_synchronous_renderer_compositor && |
| 146 needs_begin_frame != last_set_needs_begin_frame_) || |
| 147 // Always request the BeginFrame immediately if it wasn't needed before. |
| 148 (needs_begin_frame && !last_set_needs_begin_frame_) || |
| 149 // Only disable the BeginFrame after a BeginFrame where we didn't swap. |
| 150 (!needs_begin_frame && last_set_needs_begin_frame_ && |
| 151 has_pending_begin_frame_ && !state_machine_.InsideBeginFrame()) || |
| 152 // We did not draw and swap this BeginFrame, |
| 153 // so we need to explicitly request another BeginFrame. |
| 154 (needs_begin_frame && has_pending_begin_frame_ && |
| 155 !state_machine_.InsideBeginFrame()); |
137 | 156 |
138 if (needs_begin_frame_to_draw) | 157 if (needs_begin_frame_to_draw) |
139 safe_to_expect_begin_frame_ = true; | 158 safe_to_expect_begin_frame_ = true; |
140 | 159 |
141 // Determine if we need BeginFrame notifications. | 160 if (should_call_set_needs_begin_frame) { |
142 // If we do, always request the BeginFrame immediately. | |
143 // If not, only disable on the next BeginFrame to avoid unnecessary toggles. | |
144 // The synchronous renderer compositor requires immediate disables though. | |
145 if ((needs_begin_frame || | |
146 state_machine_.inside_begin_frame() || | |
147 immediate_disables_needed) && | |
148 (needs_begin_frame != last_set_needs_begin_frame_)) { | |
149 has_pending_begin_frame_ = false; | 161 has_pending_begin_frame_ = false; |
150 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); | 162 client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame); |
151 if (safe_to_expect_begin_frame_) | 163 if (safe_to_expect_begin_frame_) |
152 last_set_needs_begin_frame_ = needs_begin_frame; | 164 last_set_needs_begin_frame_ = needs_begin_frame; |
153 } | 165 } |
154 | |
155 // Request another BeginFrame if we haven't drawn for now until we have | |
156 // deadlines implemented. | |
157 if (state_machine_.inside_begin_frame() && has_pending_begin_frame_) { | |
158 has_pending_begin_frame_ = false; | |
159 client_->SetNeedsBeginFrameOnImplThread(true); | |
160 return; | |
161 } | |
162 } | 166 } |
163 | 167 |
164 void Scheduler::BeginFrame(const BeginFrameArgs& args) { | 168 void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
165 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); | 169 TRACE_EVENT0("cc", "Scheduler::BeginFrame"); |
166 DCHECK(!has_pending_begin_frame_); | 170 DCHECK(!has_pending_begin_frame_); |
167 has_pending_begin_frame_ = true; | 171 has_pending_begin_frame_ = true; |
168 safe_to_expect_begin_frame_ = true; | 172 safe_to_expect_begin_frame_ = true; |
169 last_begin_frame_args_ = args; | 173 last_begin_frame_args_ = args; |
170 state_machine_.DidEnterBeginFrame(args); | 174 last_begin_frame_args_.deadline -= client_->DrawDurationEstimate(); |
| 175 state_machine_.OnBeginFrame(last_begin_frame_args_); |
171 ProcessScheduledActions(); | 176 ProcessScheduledActions(); |
172 state_machine_.DidLeaveBeginFrame(); | 177 |
| 178 if (settings_.using_synchronous_renderer_compositor) { |
| 179 // The synchronous renderer compositor has to make it's GL calls |
| 180 // within this call to BeginFrame. |
| 181 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks |
| 182 // so the sychronous renderer compoistor can take advantage of splitting |
| 183 // up the BeginFrame and deadline as well. |
| 184 OnBeginFrameDeadline(); |
| 185 } else if (!settings_.deadline_scheduling_enabled) { |
| 186 // We emulate the old non-deadline scheduler here by posting the |
| 187 // deadline task without any delay. |
| 188 PostBeginFrameDeadline(base::TimeTicks()); |
| 189 } else if (state_machine_.ShouldTriggerBeginFrameDeadlineEarly()) { |
| 190 // We are ready to draw a new active tree immediately. |
| 191 PostBeginFrameDeadline(base::TimeTicks()); |
| 192 } else if (state_machine_.needs_redraw()) { |
| 193 // We have an animation or fast input path on the impl thread that wants |
| 194 // to draw, so don't wait too long for a new active tree. |
| 195 PostBeginFrameDeadline(last_begin_frame_args_.deadline); |
| 196 } else { |
| 197 // The impl thread doesn't have anything it wants to draw and we are just |
| 198 // waiting for a new active tree, so post the deadline for the next |
| 199 // expected BeginFrame start. |
| 200 // TODO(brianderson): Handle long deadlines (that are past the next frame's |
| 201 // frame time) properly instead of using this hack. |
| 202 PostBeginFrameDeadline(last_begin_frame_args_.frame_time + |
| 203 last_begin_frame_args_.interval); |
| 204 } |
| 205 } |
| 206 |
| 207 void Scheduler::PostBeginFrameDeadline(base::TimeTicks deadline) { |
| 208 begin_frame_deadline_closure_.Cancel(); |
| 209 begin_frame_deadline_closure_.Reset( |
| 210 base::Bind(&Scheduler::OnBeginFrameDeadline, weak_factory_.GetWeakPtr())); |
| 211 client_->PostBeginFrameDeadline(begin_frame_deadline_closure_.callback(), |
| 212 deadline); |
| 213 } |
| 214 |
| 215 void Scheduler::OnBeginFrameDeadline() { |
| 216 TRACE_EVENT0("cc", "Scheduler::OnBeginFrameDeadline"); |
| 217 begin_frame_deadline_closure_.Cancel(); |
| 218 state_machine_.OnBeginFrameDeadline(); |
| 219 ProcessScheduledActions(); |
| 220 client_->DidBeginFrameDeadlineOnImplThread(); |
173 } | 221 } |
174 | 222 |
175 void Scheduler::DrawAndSwapIfPossible() { | 223 void Scheduler::DrawAndSwapIfPossible() { |
176 DrawSwapReadbackResult result = | 224 DrawSwapReadbackResult result = |
177 client_->ScheduledActionDrawAndSwapIfPossible(); | 225 client_->ScheduledActionDrawAndSwapIfPossible(); |
178 state_machine_.DidDrawIfPossibleCompleted(result.did_draw); | 226 state_machine_.DidDrawIfPossibleCompleted(result.did_draw); |
179 if (result.did_swap) | 227 if (result.did_swap) |
180 has_pending_begin_frame_ = false; | 228 has_pending_begin_frame_ = false; |
181 } | 229 } |
182 | 230 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 break; | 281 break; |
234 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: | 282 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: |
235 client_->ScheduledActionBeginOutputSurfaceCreation(); | 283 client_->ScheduledActionBeginOutputSurfaceCreation(); |
236 break; | 284 break; |
237 case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD: | 285 case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD: |
238 client_->ScheduledActionAcquireLayerTexturesForMainThread(); | 286 client_->ScheduledActionAcquireLayerTexturesForMainThread(); |
239 break; | 287 break; |
240 } | 288 } |
241 } while (action != SchedulerStateMachine::ACTION_NONE); | 289 } while (action != SchedulerStateMachine::ACTION_NONE); |
242 | 290 |
| 291 state_machine_.AdvanceBeginFrameStateWhenNoActionsRemain(); |
243 SetupNextBeginFrameIfNeeded(); | 292 SetupNextBeginFrameIfNeeded(); |
244 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); | 293 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); |
245 } | 294 } |
246 | 295 |
247 bool Scheduler::WillDrawIfNeeded() const { | 296 bool Scheduler::WillDrawIfNeeded() const { |
248 return !state_machine_.PendingDrawsShouldBeAborted(); | 297 return !state_machine_.PendingDrawsShouldBeAborted(); |
249 } | 298 } |
250 | 299 |
251 } // namespace cc | 300 } // namespace cc |
OLD | NEW |