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