Chromium Code Reviews| 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" |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 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 entire_display_damaged_(false), | 26 entire_display_damaged_(false), |
| 27 all_active_child_surfaces_ready_to_draw_(false), | 27 all_active_child_surfaces_ready_to_draw_(false), |
| 28 pending_swaps_(0), | 28 pending_swaps_(0), |
| 29 max_pending_swaps_(max_pending_swaps), | 29 max_pending_swaps_(max_pending_swaps), |
| 30 root_surface_damaged_(false), | 30 root_surface_damaged_(false), |
| 31 expect_damage_from_root_surface_(false), | 31 root_surface_active_(false), |
| 32 current_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 30 matching lines...) Expand all Loading... | |
| 72 void DisplayScheduler::SurfaceDamaged(SurfaceId surface_id) { | 73 void DisplayScheduler::SurfaceDamaged(SurfaceId surface_id) { |
| 73 TRACE_EVENT1("cc", "DisplayScheduler::SurfaceDamaged", "surface_id", | 74 TRACE_EVENT1("cc", "DisplayScheduler::SurfaceDamaged", "surface_id", |
| 74 surface_id.id); | 75 surface_id.id); |
| 75 | 76 |
| 76 needs_draw_ = true; | 77 needs_draw_ = true; |
| 77 | 78 |
| 78 if (surface_id == root_surface_id_) { | 79 if (surface_id == root_surface_id_) { |
| 79 root_surface_damaged_ = true; | 80 root_surface_damaged_ = true; |
| 80 } else { | 81 } else { |
| 81 child_surface_ids_damaged_.insert(surface_id); | 82 child_surface_ids_damaged_.insert(surface_id); |
| 83 UpdateFutureActiveChildSurfaceIDs(surface_id); | |
|
sunnyps
2015/07/23 21:10:38
nit: Instead of a separate method, just update the
| |
| 82 | 84 |
| 83 // TODO(mithro): Use hints from SetNeedsBeginFrames and SwapAborts. | 85 // TODO(mithro): Use hints from SetNeedsBeginFrames and SwapAborts. |
| 84 all_active_child_surfaces_ready_to_draw_ = base::STLIncludes( | 86 all_active_child_surfaces_ready_to_draw_ = base::STLIncludes( |
| 85 child_surface_ids_damaged_, child_surface_ids_to_expect_damage_from_); | 87 child_surface_ids_damaged_, CurrentActiveChildSurfaceIDs()); |
| 86 } | 88 } |
| 87 | 89 |
| 88 begin_frame_source_->SetNeedsBeginFrames(!output_surface_lost_); | 90 begin_frame_source_->SetNeedsBeginFrames(!output_surface_lost_); |
| 89 ScheduleBeginFrameDeadline(); | 91 ScheduleBeginFrameDeadline(); |
| 90 } | 92 } |
| 91 | 93 |
| 92 void DisplayScheduler::OutputSurfaceLost() { | 94 void DisplayScheduler::OutputSurfaceLost() { |
| 93 TRACE_EVENT0("cc", "DisplayScheduler::OutputSurfaceLost"); | 95 TRACE_EVENT0("cc", "DisplayScheduler::OutputSurfaceLost"); |
| 94 output_surface_lost_ = true; | 96 output_surface_lost_ = true; |
| 95 begin_frame_source_->SetNeedsBeginFrames(false); | 97 begin_frame_source_->SetNeedsBeginFrames(false); |
| 96 ScheduleBeginFrameDeadline(); | 98 ScheduleBeginFrameDeadline(); |
| 97 } | 99 } |
| 98 | 100 |
| 99 void DisplayScheduler::DrawAndSwap() { | 101 void DisplayScheduler::DrawAndSwap() { |
| 100 TRACE_EVENT0("cc", "DisplayScheduler::DrawAndSwap"); | 102 TRACE_EVENT0("cc", "DisplayScheduler::DrawAndSwap"); |
| 101 DCHECK_LT(pending_swaps_, max_pending_swaps_); | 103 DCHECK_LT(pending_swaps_, max_pending_swaps_); |
| 102 DCHECK(!output_surface_lost_); | 104 DCHECK(!output_surface_lost_); |
| 103 | 105 |
| 104 bool success = client_->DrawAndSwap(); | 106 bool success = client_->DrawAndSwap(); |
| 105 if (!success) | 107 if (!success) |
| 106 return; | 108 return; |
| 107 | 109 |
| 108 child_surface_ids_to_expect_damage_from_ = | 110 UpdateActiveSurfaces(); |
|
sunnyps
2015/07/23 21:10:38
nit: No need for a separate method here. It's easi
| |
| 109 base::STLSetIntersection<std::vector<SurfaceId>>( | |
| 110 child_surface_ids_damaged_, child_surface_ids_damaged_prev_); | |
| 111 | 111 |
| 112 child_surface_ids_damaged_prev_.swap(child_surface_ids_damaged_); | 112 // Update state regarding what needs to be drawn. |
| 113 child_surface_ids_damaged_.clear(); | |
| 114 | |
| 115 needs_draw_ = false; | 113 needs_draw_ = false; |
| 116 entire_display_damaged_ = false; | 114 entire_display_damaged_ = false; |
| 117 all_active_child_surfaces_ready_to_draw_ = | |
| 118 child_surface_ids_to_expect_damage_from_.empty(); | |
| 119 | |
| 120 expect_damage_from_root_surface_ = root_surface_damaged_; | |
| 121 root_surface_damaged_ = false; | 115 root_surface_damaged_ = false; |
| 116 child_surface_ids_damaged_.clear(); | |
| 122 } | 117 } |
| 123 | 118 |
| 124 bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { | 119 bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { |
| 125 base::TimeTicks now = base::TimeTicks::Now(); | 120 base::TimeTicks now = base::TimeTicks::Now(); |
| 126 TRACE_EVENT2("cc", "DisplayScheduler::BeginFrame", "args", args.AsValue(), | 121 TRACE_EVENT2("cc", "DisplayScheduler::BeginFrame", "args", args.AsValue(), |
| 127 "now", now); | 122 "now", now); |
| 128 | 123 |
| 129 // If we get another BeginFrame before the previous deadline, | 124 // If we get another BeginFrame before the previous deadline, |
| 130 // synchronously trigger the previous deadline before progressing. | 125 // synchronously trigger the previous deadline before progressing. |
| 131 if (inside_begin_frame_deadline_interval_) { | 126 if (inside_begin_frame_deadline_interval_) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 current_begin_frame_args_.interval; | 162 current_begin_frame_args_.interval; |
| 168 } | 163 } |
| 169 | 164 |
| 170 // TODO(mithro): Be smarter about resize deadlines. | 165 // TODO(mithro): Be smarter about resize deadlines. |
| 171 if (entire_display_damaged_) { | 166 if (entire_display_damaged_) { |
| 172 TRACE_EVENT_INSTANT0("cc", "Entire display damaged", | 167 TRACE_EVENT_INSTANT0("cc", "Entire display damaged", |
| 173 TRACE_EVENT_SCOPE_THREAD); | 168 TRACE_EVENT_SCOPE_THREAD); |
| 174 return base::TimeTicks(); | 169 return base::TimeTicks(); |
| 175 } | 170 } |
| 176 | 171 |
| 177 bool root_ready_to_draw = | 172 bool root_ready_to_draw = !root_surface_active_ || root_surface_damaged_; |
| 178 !expect_damage_from_root_surface_ || root_surface_damaged_; | |
| 179 | 173 |
| 180 if (all_active_child_surfaces_ready_to_draw_ && root_ready_to_draw) { | 174 if (all_active_child_surfaces_ready_to_draw_ && root_ready_to_draw) { |
| 181 TRACE_EVENT_INSTANT0("cc", "All active surfaces ready", | 175 TRACE_EVENT_INSTANT0("cc", "All active surfaces ready", |
| 182 TRACE_EVENT_SCOPE_THREAD); | 176 TRACE_EVENT_SCOPE_THREAD); |
| 183 return base::TimeTicks(); | 177 return base::TimeTicks(); |
| 184 } | 178 } |
| 185 | 179 |
| 186 // Use an earlier deadline if we are only waiting for the root surface | 180 // Use an earlier deadline if we are only waiting for the root surface |
| 187 // in case our expect_damage_from_root_surface heuristic is incorrect. | 181 // in case our expect_damage_from_root_surface heuristic is incorrect. |
| 188 // TODO(mithro): Replace this with SetNeedsBeginFrame and SwapAbort | 182 // TODO(mithro): Replace this with SetNeedsBeginFrame and SwapAbort |
| 189 // logic. | 183 // logic. |
| 190 if (all_active_child_surfaces_ready_to_draw_ && | 184 if (all_active_child_surfaces_ready_to_draw_ && root_surface_active_) { |
|
sunnyps
2015/07/23 21:10:38
nit: Rename to child_surfaces_ready_to_draw_
brianderson
2015/07/23 22:21:48
Done.
| |
| 191 expect_damage_from_root_surface_) { | |
| 192 TRACE_EVENT_INSTANT0("cc", "Waiting for damage from root surface", | 185 TRACE_EVENT_INSTANT0("cc", "Waiting for damage from root surface", |
| 193 TRACE_EVENT_SCOPE_THREAD); | 186 TRACE_EVENT_SCOPE_THREAD); |
| 194 // This adjusts the deadline by DefaultEstimatedParentDrawTime for | 187 // This adjusts the deadline by DefaultEstimatedParentDrawTime for |
| 195 // a second time. The first one represented the Surfaces draw to display | 188 // a second time. The first one represented the Surfaces draw to display |
| 196 // latency. This one represents root surface commit+raster+draw latency. | 189 // latency. This one represents root surface commit+raster+draw latency. |
| 197 // We treat the root surface differently since it lives on the same thread | 190 // We treat the root surface differently since it lives on the same thread |
| 198 // as Surfaces and waiting for it too long may push out the Surfaces draw. | 191 // as Surfaces and waiting for it too long may push out the Surfaces draw. |
| 199 // If we also assume the root surface is fast to start a commit after the | 192 // If we also assume the root surface is fast to start a commit after the |
| 200 // beginning of a frame, it'll have a chance to lock its resources, which | 193 // beginning of a frame, it'll have a chance to lock its resources, which |
| 201 // will cause us to wait for it to unlock its resources above. | 194 // 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... | |
| 242 begin_frame_deadline_task_.callback(), delta); | 235 begin_frame_deadline_task_.callback(), delta); |
| 243 TRACE_EVENT2("cc", "Using new deadline", "delta", delta.ToInternalValue(), | 236 TRACE_EVENT2("cc", "Using new deadline", "delta", delta.ToInternalValue(), |
| 244 "desired_deadline", desired_deadline); | 237 "desired_deadline", desired_deadline); |
| 245 } | 238 } |
| 246 | 239 |
| 247 void DisplayScheduler::AttemptDrawAndSwap() { | 240 void DisplayScheduler::AttemptDrawAndSwap() { |
| 248 inside_begin_frame_deadline_interval_ = false; | 241 inside_begin_frame_deadline_interval_ = false; |
| 249 begin_frame_deadline_task_.Cancel(); | 242 begin_frame_deadline_task_.Cancel(); |
| 250 begin_frame_deadline_task_time_ = base::TimeTicks(); | 243 begin_frame_deadline_task_time_ = base::TimeTicks(); |
| 251 | 244 |
| 252 if (needs_draw_ && !output_surface_lost_) { | 245 bool stay_active = |
| 253 if (pending_swaps_ < max_pending_swaps_ && !root_surface_resources_locked_) | 246 !output_surface_lost_ && (needs_draw_ || root_surface_active_ || |
| 254 DrawAndSwap(); | 247 !CurrentActiveChildSurfaceIDs().empty()); |
| 248 | |
|
sunnyps
2015/07/23 21:10:38
nit: This could be better structured as:
if (!sta
brianderson
2015/07/23 22:21:48
Done.
| |
| 249 if (stay_active) { | |
| 250 if (needs_draw_) { | |
| 251 if (pending_swaps_ < max_pending_swaps_ && | |
| 252 !root_surface_resources_locked_) | |
| 253 DrawAndSwap(); | |
| 254 } else { | |
| 255 // In order to properly go idle, make sure to update expectations that | |
| 256 // will cause |stay_active| to go false even if we have nothing to draw. | |
| 257 // Verify no child surfaces are currently damaged, since | |
| 258 // UpdateSurfaceDamageExpectatations will clear that list. | |
| 259 DCHECK(child_surface_ids_damaged_.empty()); | |
| 260 DCHECK(!entire_display_damaged_); | |
| 261 DCHECK(!root_surface_damaged_); | |
| 262 UpdateActiveSurfaces(); | |
| 263 } | |
| 255 } else { | 264 } else { |
| 256 // We are going idle, so reset expectations. | 265 // We are going idle, so reset expectations. |
| 257 child_surface_ids_to_expect_damage_from_.clear(); | 266 ClearActiveSurfaces(); |
|
sunnyps
2015/07/23 21:10:38
nit: Probably doesn't need a separate method.
| |
| 258 child_surface_ids_damaged_prev_.clear(); | |
| 259 child_surface_ids_damaged_.clear(); | |
| 260 all_active_child_surfaces_ready_to_draw_ = true; | |
| 261 expect_damage_from_root_surface_ = false; | |
| 262 | |
| 263 begin_frame_source_->SetNeedsBeginFrames(false); | 267 begin_frame_source_->SetNeedsBeginFrames(false); |
| 264 } | 268 } |
| 265 } | 269 } |
| 266 | 270 |
| 267 void DisplayScheduler::OnBeginFrameDeadline() { | 271 void DisplayScheduler::OnBeginFrameDeadline() { |
| 268 TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline"); | 272 TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline"); |
| 269 | 273 |
| 270 AttemptDrawAndSwap(); | 274 AttemptDrawAndSwap(); |
| 271 begin_frame_source_->DidFinishFrame(0); | 275 begin_frame_source_->DidFinishFrame(0); |
| 272 } | 276 } |
| 273 | 277 |
| 274 void DisplayScheduler::DidSwapBuffers() { | 278 void DisplayScheduler::DidSwapBuffers() { |
| 275 pending_swaps_++; | 279 pending_swaps_++; |
| 276 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffers", "pending_frames", | 280 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffers", "pending_frames", |
| 277 pending_swaps_); | 281 pending_swaps_); |
| 278 } | 282 } |
| 279 | 283 |
| 280 void DisplayScheduler::DidSwapBuffersComplete() { | 284 void DisplayScheduler::DidSwapBuffersComplete() { |
| 281 pending_swaps_--; | 285 pending_swaps_--; |
| 282 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffersComplete", | 286 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffersComplete", |
| 283 "pending_frames", pending_swaps_); | 287 "pending_frames", pending_swaps_); |
| 284 ScheduleBeginFrameDeadline(); | 288 ScheduleBeginFrameDeadline(); |
| 285 } | 289 } |
| 286 | 290 |
| 291 std::set<SurfaceId>& DisplayScheduler::CurrentActiveChildSurfaceIDs() { | |
|
sunnyps
2015/07/23 21:10:38
nit: inline this
| |
| 292 return active_child_surface_ids_[current_active_child_surface_ids_index_]; | |
| 293 } | |
| 294 | |
| 295 void DisplayScheduler::UpdateFutureActiveChildSurfaceIDs(SurfaceId surface_id) { | |
| 296 for (int i = 0; i < kActiveChildSurfaceIdsSize; i++) | |
| 297 active_child_surface_ids_[i].insert(surface_id); | |
| 298 } | |
| 299 | |
| 300 void DisplayScheduler::ClearActiveSurfaces() { | |
| 301 root_surface_active_ = false; | |
| 302 | |
| 303 current_active_child_surface_ids_index_ = 0; | |
| 304 for (int i = 0; i < kActiveChildSurfaceIdsSize; i++) | |
| 305 active_child_surface_ids_[i].clear(); | |
| 306 | |
| 307 all_active_child_surfaces_ready_to_draw_ = true; | |
| 308 } | |
| 309 | |
| 310 void DisplayScheduler::UpdateActiveSurfaces() { | |
| 311 root_surface_active_ = root_surface_damaged_; | |
| 312 | |
| 313 CurrentActiveChildSurfaceIDs().clear(); | |
| 314 | |
| 315 current_active_child_surface_ids_index_++; | |
|
sunnyps
2015/07/23 21:10:38
nit: index = (index + 1) % N
brianderson
2015/07/23 22:21:49
Done.
| |
| 316 if (current_active_child_surface_ids_index_ >= kActiveChildSurfaceIdsSize) | |
| 317 current_active_child_surface_ids_index_ = 0; | |
| 318 | |
| 319 all_active_child_surfaces_ready_to_draw_ = | |
|
sunnyps
2015/07/23 21:10:38
nit: This could be an inline function.
brianderson
2015/07/23 22:21:48
My goal in writing all the helper methods was to p
| |
| 320 CurrentActiveChildSurfaceIDs().empty(); | |
| 321 } | |
| 322 | |
| 287 } // namespace cc | 323 } // namespace cc |
| OLD | NEW |