OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/surfaces/display_scheduler.h" | 5 #include "cc/surfaces/display_scheduler.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.h" |
11 #include "cc/output/output_surface.h" | 11 #include "cc/output/output_surface.h" |
12 | 12 |
13 namespace cc { | 13 namespace cc { |
14 | 14 |
15 DisplayScheduler::DisplayScheduler(DisplaySchedulerClient* client, | 15 DisplayScheduler::DisplayScheduler(DisplaySchedulerClient* client, |
16 BeginFrameSource* begin_frame_source, | 16 BeginFrameSource* begin_frame_source, |
17 base::SingleThreadTaskRunner* task_runner, | 17 base::SingleThreadTaskRunner* task_runner, |
18 int max_pending_swaps) | 18 int max_pending_swaps) |
19 : client_(client), | 19 : client_(client), |
20 begin_frame_source_(begin_frame_source), | 20 begin_frame_source_(begin_frame_source), |
21 task_runner_(task_runner), | 21 task_runner_(task_runner), |
22 output_surface_lost_(false), | 22 output_surface_lost_(false), |
23 root_surface_resources_locked_(true), | 23 root_surface_resources_locked_(true), |
24 inside_begin_frame_deadline_interval_(false), | 24 inside_begin_frame_deadline_interval_(false), |
25 needs_draw_(false), | 25 needs_draw_(false), |
26 child_surfaces_ready_to_draw_(false), | 26 expecting_root_surface_damage_because_of_resize_(false), |
| 27 all_active_child_surfaces_ready_to_draw_(false), |
27 pending_swaps_(0), | 28 pending_swaps_(0), |
28 max_pending_swaps_(max_pending_swaps), | 29 max_pending_swaps_(max_pending_swaps), |
29 root_surface_damaged_(false), | 30 root_surface_damaged_(false), |
30 root_surface_active_(false), | 31 expect_damage_from_root_surface_(false), |
31 expecting_root_surface_damage_because_of_resize_(false), | |
32 active_child_surface_ids_index_(0), | |
33 weak_ptr_factory_(this) { | 32 weak_ptr_factory_(this) { |
34 begin_frame_source_->AddObserver(this); | 33 begin_frame_source_->AddObserver(this); |
35 begin_frame_deadline_closure_ = base::Bind( | 34 begin_frame_deadline_closure_ = base::Bind( |
36 &DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr()); | 35 &DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr()); |
37 } | 36 } |
38 | 37 |
39 DisplayScheduler::~DisplayScheduler() { | 38 DisplayScheduler::~DisplayScheduler() { |
40 begin_frame_source_->RemoveObserver(this); | 39 begin_frame_source_->RemoveObserver(this); |
41 } | 40 } |
42 | 41 |
(...skipping 10 matching lines...) Expand all Loading... |
53 void DisplayScheduler::ForceImmediateSwapIfPossible() { | 52 void DisplayScheduler::ForceImmediateSwapIfPossible() { |
54 TRACE_EVENT0("cc", "DisplayScheduler::ForceImmediateSwapIfPossible"); | 53 TRACE_EVENT0("cc", "DisplayScheduler::ForceImmediateSwapIfPossible"); |
55 bool in_begin = inside_begin_frame_deadline_interval_; | 54 bool in_begin = inside_begin_frame_deadline_interval_; |
56 AttemptDrawAndSwap(); | 55 AttemptDrawAndSwap(); |
57 if (in_begin) | 56 if (in_begin) |
58 begin_frame_source_->DidFinishFrame(0); | 57 begin_frame_source_->DidFinishFrame(0); |
59 } | 58 } |
60 | 59 |
61 void DisplayScheduler::DisplayResized() { | 60 void DisplayScheduler::DisplayResized() { |
62 expecting_root_surface_damage_because_of_resize_ = true; | 61 expecting_root_surface_damage_because_of_resize_ = true; |
63 root_surface_active_ = true; | 62 expect_damage_from_root_surface_ = true; |
64 ScheduleBeginFrameDeadline(); | 63 ScheduleBeginFrameDeadline(); |
65 } | 64 } |
66 | 65 |
67 // Notification that there was a resize or the root surface changed and | 66 // Notification that there was a resize or the root surface changed and |
68 // that we should just draw immediately. | 67 // that we should just draw immediately. |
69 void DisplayScheduler::SetNewRootSurface(SurfaceId root_surface_id) { | 68 void DisplayScheduler::SetNewRootSurface(SurfaceId root_surface_id) { |
70 TRACE_EVENT0("cc", "DisplayScheduler::SetNewRootSurface"); | 69 TRACE_EVENT0("cc", "DisplayScheduler::SetNewRootSurface"); |
71 root_surface_id_ = root_surface_id; | 70 root_surface_id_ = root_surface_id; |
72 SurfaceDamaged(root_surface_id); | 71 SurfaceDamaged(root_surface_id); |
73 } | 72 } |
74 | 73 |
75 // Indicates that there was damage to one of the surfaces. | 74 // Indicates that there was damage to one of the surfaces. |
76 // Has some logic to wait for multiple active surfaces before | 75 // Has some logic to wait for multiple active surfaces before |
77 // triggering the deadline. | 76 // triggering the deadline. |
78 void DisplayScheduler::SurfaceDamaged(SurfaceId surface_id) { | 77 void DisplayScheduler::SurfaceDamaged(SurfaceId surface_id) { |
79 TRACE_EVENT1("cc", "DisplayScheduler::SurfaceDamaged", "surface_id", | 78 TRACE_EVENT1("cc", "DisplayScheduler::SurfaceDamaged", "surface_id", |
80 surface_id.id); | 79 surface_id.id); |
81 | 80 |
82 needs_draw_ = true; | 81 needs_draw_ = true; |
83 | 82 |
84 if (surface_id == root_surface_id_) { | 83 if (surface_id == root_surface_id_) { |
85 root_surface_damaged_ = true; | 84 root_surface_damaged_ = true; |
86 expecting_root_surface_damage_because_of_resize_ = false; | 85 expecting_root_surface_damage_because_of_resize_ = false; |
87 } else { | 86 } else { |
88 child_surface_ids_damaged_.insert(surface_id); | 87 child_surface_ids_damaged_.insert(surface_id); |
89 | 88 |
90 // Update future expectations for active child surfaces. | |
91 for (int i = 0; i < kNumFramesSurfaceIsActive; i++) | |
92 active_child_surface_ids_[i].insert(surface_id); | |
93 | |
94 // TODO(mithro): Use hints from SetNeedsBeginFrames and SwapAborts. | 89 // TODO(mithro): Use hints from SetNeedsBeginFrames and SwapAborts. |
95 child_surfaces_ready_to_draw_ = base::STLIncludes( | 90 all_active_child_surfaces_ready_to_draw_ = base::STLIncludes( |
96 child_surface_ids_damaged_, | 91 child_surface_ids_damaged_, child_surface_ids_to_expect_damage_from_); |
97 active_child_surface_ids_[active_child_surface_ids_index_]); | |
98 } | 92 } |
99 | 93 |
100 begin_frame_source_->SetNeedsBeginFrames(!output_surface_lost_); | 94 begin_frame_source_->SetNeedsBeginFrames(!output_surface_lost_); |
101 ScheduleBeginFrameDeadline(); | 95 ScheduleBeginFrameDeadline(); |
102 } | 96 } |
103 | 97 |
104 void DisplayScheduler::OutputSurfaceLost() { | 98 void DisplayScheduler::OutputSurfaceLost() { |
105 TRACE_EVENT0("cc", "DisplayScheduler::OutputSurfaceLost"); | 99 TRACE_EVENT0("cc", "DisplayScheduler::OutputSurfaceLost"); |
106 output_surface_lost_ = true; | 100 output_surface_lost_ = true; |
107 begin_frame_source_->SetNeedsBeginFrames(false); | 101 begin_frame_source_->SetNeedsBeginFrames(false); |
108 ScheduleBeginFrameDeadline(); | 102 ScheduleBeginFrameDeadline(); |
109 } | 103 } |
110 | 104 |
111 void DisplayScheduler::DrawAndSwap() { | 105 void DisplayScheduler::DrawAndSwap() { |
112 TRACE_EVENT0("cc", "DisplayScheduler::DrawAndSwap"); | 106 TRACE_EVENT0("cc", "DisplayScheduler::DrawAndSwap"); |
113 DCHECK_LT(pending_swaps_, max_pending_swaps_); | 107 DCHECK_LT(pending_swaps_, max_pending_swaps_); |
114 DCHECK(!output_surface_lost_); | 108 DCHECK(!output_surface_lost_); |
115 | 109 |
116 bool success = client_->DrawAndSwap(); | 110 bool success = client_->DrawAndSwap(); |
117 if (!success) | 111 if (!success) |
118 return; | 112 return; |
119 | 113 |
120 UpdateActiveSurfaces(); | 114 child_surface_ids_to_expect_damage_from_ = |
| 115 base::STLSetIntersection<std::vector<SurfaceId>>( |
| 116 child_surface_ids_damaged_, child_surface_ids_damaged_prev_); |
121 | 117 |
122 // Update state regarding what needs to be drawn. | 118 child_surface_ids_damaged_prev_.swap(child_surface_ids_damaged_); |
| 119 child_surface_ids_damaged_.clear(); |
| 120 |
123 needs_draw_ = false; | 121 needs_draw_ = false; |
| 122 all_active_child_surfaces_ready_to_draw_ = |
| 123 child_surface_ids_to_expect_damage_from_.empty(); |
| 124 |
| 125 expect_damage_from_root_surface_ = root_surface_damaged_; |
124 root_surface_damaged_ = false; | 126 root_surface_damaged_ = false; |
125 child_surface_ids_damaged_.clear(); | |
126 } | 127 } |
127 | 128 |
128 bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { | 129 bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { |
129 base::TimeTicks now = base::TimeTicks::Now(); | 130 base::TimeTicks now = base::TimeTicks::Now(); |
130 TRACE_EVENT2("cc", "DisplayScheduler::BeginFrame", "args", args.AsValue(), | 131 TRACE_EVENT2("cc", "DisplayScheduler::BeginFrame", "args", args.AsValue(), |
131 "now", now); | 132 "now", now); |
132 | 133 |
133 // If we get another BeginFrame before the previous deadline, | 134 // If we get another BeginFrame before the previous deadline, |
134 // synchronously trigger the previous deadline before progressing. | 135 // synchronously trigger the previous deadline before progressing. |
135 if (inside_begin_frame_deadline_interval_) { | 136 if (inside_begin_frame_deadline_interval_) { |
(...skipping 28 matching lines...) Expand all Loading... |
164 current_begin_frame_args_.interval; | 165 current_begin_frame_args_.interval; |
165 } | 166 } |
166 | 167 |
167 if (root_surface_resources_locked_) { | 168 if (root_surface_resources_locked_) { |
168 TRACE_EVENT_INSTANT0("cc", "Root surface resources locked", | 169 TRACE_EVENT_INSTANT0("cc", "Root surface resources locked", |
169 TRACE_EVENT_SCOPE_THREAD); | 170 TRACE_EVENT_SCOPE_THREAD); |
170 return current_begin_frame_args_.frame_time + | 171 return current_begin_frame_args_.frame_time + |
171 current_begin_frame_args_.interval; | 172 current_begin_frame_args_.interval; |
172 } | 173 } |
173 | 174 |
174 bool root_ready_to_draw = !root_surface_active_ || root_surface_damaged_; | 175 bool root_ready_to_draw = |
| 176 !expect_damage_from_root_surface_ || root_surface_damaged_; |
175 | 177 |
176 if (child_surfaces_ready_to_draw_ && root_ready_to_draw) { | 178 if (all_active_child_surfaces_ready_to_draw_ && root_ready_to_draw) { |
177 TRACE_EVENT_INSTANT0("cc", "All active surfaces ready", | 179 TRACE_EVENT_INSTANT0("cc", "All active surfaces ready", |
178 TRACE_EVENT_SCOPE_THREAD); | 180 TRACE_EVENT_SCOPE_THREAD); |
179 return base::TimeTicks(); | 181 return base::TimeTicks(); |
180 } | 182 } |
181 | 183 |
182 // TODO(mithro): Be smarter about resize deadlines. | 184 // TODO(mithro): Be smarter about resize deadlines. |
183 if (expecting_root_surface_damage_because_of_resize_) { | 185 if (expecting_root_surface_damage_because_of_resize_) { |
184 TRACE_EVENT_INSTANT0("cc", "Entire display damaged", | 186 TRACE_EVENT_INSTANT0("cc", "Entire display damaged", |
185 TRACE_EVENT_SCOPE_THREAD); | 187 TRACE_EVENT_SCOPE_THREAD); |
186 return current_begin_frame_args_.frame_time + | 188 return current_begin_frame_args_.frame_time + |
187 current_begin_frame_args_.interval; | 189 current_begin_frame_args_.interval; |
188 } | 190 } |
189 | 191 |
190 // Use an earlier deadline if we are only waiting for the root surface | 192 // Use an earlier deadline if we are only waiting for the root surface |
191 // in case our expect_damage_from_root_surface heuristic is incorrect. | 193 // in case our expect_damage_from_root_surface heuristic is incorrect. |
192 // TODO(mithro): Replace this with SetNeedsBeginFrame and SwapAbort | 194 // TODO(mithro): Replace this with SetNeedsBeginFrame and SwapAbort |
193 // logic. | 195 // logic. |
194 if (child_surfaces_ready_to_draw_ && root_surface_active_) { | 196 if (all_active_child_surfaces_ready_to_draw_ && |
| 197 expect_damage_from_root_surface_) { |
195 TRACE_EVENT_INSTANT0("cc", "Waiting for damage from root surface", | 198 TRACE_EVENT_INSTANT0("cc", "Waiting for damage from root surface", |
196 TRACE_EVENT_SCOPE_THREAD); | 199 TRACE_EVENT_SCOPE_THREAD); |
197 // This adjusts the deadline by DefaultEstimatedParentDrawTime for | 200 // This adjusts the deadline by DefaultEstimatedParentDrawTime for |
198 // a second time. The first one represented the Surfaces draw to display | 201 // a second time. The first one represented the Surfaces draw to display |
199 // latency. This one represents root surface commit+raster+draw latency. | 202 // latency. This one represents root surface commit+raster+draw latency. |
200 // We treat the root surface differently since it lives on the same thread | 203 // We treat the root surface differently since it lives on the same thread |
201 // as Surfaces and waiting for it too long may push out the Surfaces draw. | 204 // as Surfaces and waiting for it too long may push out the Surfaces draw. |
202 // If we also assume the root surface is fast to start a commit after the | 205 // If we also assume the root surface is fast to start a commit after the |
203 // beginning of a frame, it'll have a chance to lock its resources, which | 206 // beginning of a frame, it'll have a chance to lock its resources, which |
204 // will cause us to wait for it to unlock its resources above. | 207 // will cause us to wait for it to unlock its resources above. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 begin_frame_deadline_task_.callback(), delta); | 248 begin_frame_deadline_task_.callback(), delta); |
246 TRACE_EVENT2("cc", "Using new deadline", "delta", delta.ToInternalValue(), | 249 TRACE_EVENT2("cc", "Using new deadline", "delta", delta.ToInternalValue(), |
247 "desired_deadline", desired_deadline); | 250 "desired_deadline", desired_deadline); |
248 } | 251 } |
249 | 252 |
250 void DisplayScheduler::AttemptDrawAndSwap() { | 253 void DisplayScheduler::AttemptDrawAndSwap() { |
251 inside_begin_frame_deadline_interval_ = false; | 254 inside_begin_frame_deadline_interval_ = false; |
252 begin_frame_deadline_task_.Cancel(); | 255 begin_frame_deadline_task_.Cancel(); |
253 begin_frame_deadline_task_time_ = base::TimeTicks(); | 256 begin_frame_deadline_task_time_ = base::TimeTicks(); |
254 | 257 |
255 bool stay_active = | 258 if (needs_draw_ && !output_surface_lost_) { |
256 !output_surface_lost_ && | 259 if (pending_swaps_ < max_pending_swaps_ && !root_surface_resources_locked_) |
257 (needs_draw_ || root_surface_active_ || | 260 DrawAndSwap(); |
258 !active_child_surface_ids_[active_child_surface_ids_index_].empty()); | 261 } else { |
| 262 // We are going idle, so reset expectations. |
| 263 child_surface_ids_to_expect_damage_from_.clear(); |
| 264 child_surface_ids_damaged_prev_.clear(); |
| 265 child_surface_ids_damaged_.clear(); |
| 266 all_active_child_surfaces_ready_to_draw_ = true; |
| 267 expect_damage_from_root_surface_ = false; |
259 | 268 |
260 if (!stay_active) { | |
261 // We are going idle, so reset expectations. | |
262 root_surface_active_ = false; | |
263 child_surfaces_ready_to_draw_ = true; | |
264 active_child_surface_ids_index_ = 0; | |
265 for (int i = 0; i < kNumFramesSurfaceIsActive; i++) | |
266 active_child_surface_ids_[i].clear(); | |
267 begin_frame_source_->SetNeedsBeginFrames(false); | 269 begin_frame_source_->SetNeedsBeginFrames(false); |
268 return; | |
269 } | 270 } |
270 | |
271 if (!needs_draw_) { | |
272 // In order to properly go idle, make sure to update expectations that | |
273 // will cause |stay_active| to go false even if we have nothing to draw. | |
274 // Verify no child surfaces are currently damaged, since | |
275 // UpdateSurfaceDamageExpectatations will clear that list. | |
276 DCHECK(child_surface_ids_damaged_.empty()); | |
277 DCHECK(!root_surface_damaged_); | |
278 UpdateActiveSurfaces(); | |
279 return; | |
280 } | |
281 | |
282 if (pending_swaps_ >= max_pending_swaps_ || root_surface_resources_locked_) | |
283 return; | |
284 | |
285 DrawAndSwap(); | |
286 } | 271 } |
287 | 272 |
288 void DisplayScheduler::OnBeginFrameDeadline() { | 273 void DisplayScheduler::OnBeginFrameDeadline() { |
289 TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline"); | 274 TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline"); |
290 | 275 |
291 AttemptDrawAndSwap(); | 276 AttemptDrawAndSwap(); |
292 begin_frame_source_->DidFinishFrame(0); | 277 begin_frame_source_->DidFinishFrame(0); |
293 } | 278 } |
294 | 279 |
295 void DisplayScheduler::DidSwapBuffers() { | 280 void DisplayScheduler::DidSwapBuffers() { |
296 pending_swaps_++; | 281 pending_swaps_++; |
297 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffers", "pending_frames", | 282 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffers", "pending_frames", |
298 pending_swaps_); | 283 pending_swaps_); |
299 } | 284 } |
300 | 285 |
301 void DisplayScheduler::DidSwapBuffersComplete() { | 286 void DisplayScheduler::DidSwapBuffersComplete() { |
302 pending_swaps_--; | 287 pending_swaps_--; |
303 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffersComplete", | 288 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffersComplete", |
304 "pending_frames", pending_swaps_); | 289 "pending_frames", pending_swaps_); |
305 ScheduleBeginFrameDeadline(); | 290 ScheduleBeginFrameDeadline(); |
306 } | 291 } |
307 | 292 |
308 void DisplayScheduler::UpdateActiveSurfaces() { | |
309 root_surface_active_ = root_surface_damaged_; | |
310 active_child_surface_ids_[active_child_surface_ids_index_].clear(); | |
311 active_child_surface_ids_index_ = | |
312 (active_child_surface_ids_index_ + 1) % kNumFramesSurfaceIsActive; | |
313 child_surfaces_ready_to_draw_ = | |
314 active_child_surface_ids_[active_child_surface_ids_index_].empty(); | |
315 } | |
316 | |
317 } // namespace cc | 293 } // namespace cc |
OLD | NEW |