| 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/auto_reset.h" | 9 #include "base/auto_reset.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 11 #include "base/trace_event/trace_event.h" | 11 #include "base/trace_event/trace_event.h" |
| 12 #include "cc/output/begin_frame_args.h" |
| 12 #include "cc/output/output_surface.h" | 13 #include "cc/output/output_surface.h" |
| 13 | 14 |
| 14 namespace cc { | 15 namespace cc { |
| 15 | 16 |
| 16 DisplayScheduler::DisplayScheduler(BeginFrameSource* begin_frame_source, | 17 DisplayScheduler::DisplayScheduler(base::SingleThreadTaskRunner* task_runner, |
| 17 base::SingleThreadTaskRunner* task_runner, | |
| 18 int max_pending_swaps) | 18 int max_pending_swaps) |
| 19 : begin_frame_source_(begin_frame_source), | 19 : client_(nullptr), |
| 20 begin_frame_source_(nullptr), |
| 20 task_runner_(task_runner), | 21 task_runner_(task_runner), |
| 21 inside_surface_damaged_(false), | 22 inside_surface_damaged_(false), |
| 22 visible_(false), | 23 visible_(false), |
| 23 output_surface_lost_(false), | 24 output_surface_lost_(false), |
| 24 root_surface_resources_locked_(true), | 25 root_surface_resources_locked_(true), |
| 25 inside_begin_frame_deadline_interval_(false), | 26 inside_begin_frame_deadline_interval_(false), |
| 26 needs_draw_(false), | 27 needs_draw_(false), |
| 27 expecting_root_surface_damage_because_of_resize_(false), | 28 expecting_root_surface_damage_because_of_resize_(false), |
| 28 all_active_child_surfaces_ready_to_draw_(false), | 29 all_active_child_surfaces_ready_to_draw_(false), |
| 29 pending_swaps_(0), | 30 pending_swaps_(0), |
| 30 max_pending_swaps_(max_pending_swaps), | 31 max_pending_swaps_(max_pending_swaps), |
| 31 observing_begin_frame_source_(false), | 32 observing_begin_frame_source_(false), |
| 32 root_surface_damaged_(false), | 33 root_surface_damaged_(false), |
| 33 expect_damage_from_root_surface_(false), | 34 expect_damage_from_root_surface_(false), |
| 34 weak_ptr_factory_(this) { | 35 weak_ptr_factory_(this) { |
| 35 begin_frame_deadline_closure_ = base::Bind( | 36 begin_frame_deadline_closure_ = base::Bind( |
| 36 &DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr()); | 37 &DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr()); |
| 37 } | 38 } |
| 38 | 39 |
| 39 DisplayScheduler::~DisplayScheduler() { | 40 DisplayScheduler::~DisplayScheduler() { |
| 40 StopObservingBeginFrames(); | 41 StopObservingBeginFrames(); |
| 41 } | 42 } |
| 42 | 43 |
| 43 void DisplayScheduler::SetClient(DisplaySchedulerClient* client) { | 44 void DisplayScheduler::SetClient(DisplaySchedulerClient* client) { |
| 44 client_ = client; | 45 client_ = client; |
| 45 } | 46 } |
| 46 | 47 |
| 48 void DisplayScheduler::SetBeginFrameSource( |
| 49 DisplayBeginFrameSource* begin_frame_source) { |
| 50 begin_frame_source_ = begin_frame_source; |
| 51 begin_frame_source_->SetClient(this); |
| 52 DCHECK(begin_frame_source_->GetTargetSource()); |
| 53 } |
| 54 |
| 47 void DisplayScheduler::SetVisible(bool visible) { | 55 void DisplayScheduler::SetVisible(bool visible) { |
| 48 if (visible_ == visible) | 56 if (visible_ == visible) |
| 49 return; | 57 return; |
| 50 | 58 |
| 51 visible_ = visible; | 59 visible_ = visible; |
| 52 // If going invisible, we'll stop observing begin frames once we try | 60 // If going invisible, we'll stop observing begin frames once we try |
| 53 // to draw and fail. | 61 // to draw and fail. |
| 54 StartObservingBeginFrames(); | 62 StartObservingBeginFrames(); |
| 55 ScheduleBeginFrameDeadline(); | 63 ScheduleBeginFrameDeadline(); |
| 56 } | 64 } |
| 57 | 65 |
| 58 // If we try to draw when the root surface resources are locked, the | 66 // If we try to draw when the root surface resources are locked, the |
| 59 // draw will fail. | 67 // draw will fail. |
| 60 void DisplayScheduler::SetRootSurfaceResourcesLocked(bool locked) { | 68 void DisplayScheduler::SetRootSurfaceResourcesLocked(bool locked) { |
| 61 TRACE_EVENT1("cc", "DisplayScheduler::SetRootSurfaceResourcesLocked", | 69 TRACE_EVENT1("cc", "DisplayScheduler::SetRootSurfaceResourcesLocked", |
| 62 "locked", locked); | 70 "locked", locked); |
| 63 root_surface_resources_locked_ = locked; | 71 root_surface_resources_locked_ = locked; |
| 64 ScheduleBeginFrameDeadline(); | 72 ScheduleBeginFrameDeadline(); |
| 65 } | 73 } |
| 66 | 74 |
| 67 // This is used to force an immediate swap before a resize. | 75 // This is used to force an immediate swap before a resize. |
| 68 void DisplayScheduler::ForceImmediateSwapIfPossible() { | 76 void DisplayScheduler::ForceImmediateSwapIfPossible() { |
| 69 TRACE_EVENT0("cc", "DisplayScheduler::ForceImmediateSwapIfPossible"); | 77 TRACE_EVENT0("cc", "DisplayScheduler::ForceImmediateSwapIfPossible"); |
| 70 bool in_begin = inside_begin_frame_deadline_interval_; | 78 bool in_begin = inside_begin_frame_deadline_interval_; |
| 71 AttemptDrawAndSwap(); | 79 AttemptDrawAndSwap(); |
| 72 if (in_begin) | 80 if (in_begin) |
| 73 begin_frame_source_->DidFinishFrame(this, 0); | 81 begin_frame_source_->GetTargetSource()->DidFinishFrame(this, 0); |
| 74 } | 82 } |
| 75 | 83 |
| 76 void DisplayScheduler::DisplayResized() { | 84 void DisplayScheduler::DisplayResized() { |
| 77 expecting_root_surface_damage_because_of_resize_ = true; | 85 expecting_root_surface_damage_because_of_resize_ = true; |
| 78 expect_damage_from_root_surface_ = true; | 86 expect_damage_from_root_surface_ = true; |
| 79 needs_draw_ = true; | 87 needs_draw_ = true; |
| 80 ScheduleBeginFrameDeadline(); | 88 ScheduleBeginFrameDeadline(); |
| 81 } | 89 } |
| 82 | 90 |
| 83 // Notification that there was a resize or the root surface changed and | 91 // Notification that there was a resize or the root surface changed and |
| (...skipping 17 matching lines...) Expand all Loading... |
| 101 base::AutoReset<bool> auto_reset(&inside_surface_damaged_, true); | 109 base::AutoReset<bool> auto_reset(&inside_surface_damaged_, true); |
| 102 | 110 |
| 103 needs_draw_ = true; | 111 needs_draw_ = true; |
| 104 | 112 |
| 105 if (surface_id == root_surface_id_) { | 113 if (surface_id == root_surface_id_) { |
| 106 root_surface_damaged_ = true; | 114 root_surface_damaged_ = true; |
| 107 expecting_root_surface_damage_because_of_resize_ = false; | 115 expecting_root_surface_damage_because_of_resize_ = false; |
| 108 } else { | 116 } else { |
| 109 child_surface_ids_damaged_.insert(surface_id); | 117 child_surface_ids_damaged_.insert(surface_id); |
| 110 | 118 |
| 111 // TODO(mithro): Use hints from SetNeedsBeginFrames and SwapAborts. | 119 if (BeginFrameForcesDamage()) { |
| 112 all_active_child_surfaces_ready_to_draw_ = base::STLIncludes( | 120 // Wait for all BeginFrameObservers to call DidFinishFrame() before |
| 113 child_surface_ids_damaged_, child_surface_ids_to_expect_damage_from_); | 121 // triggering an early deadline. We do this only if we know that the |
| 122 // BeginFrame should cause damage on all active surfaces, because BFOs |
| 123 // currently may not call DidFinishFrame() when the BeginFrame does not |
| 124 // cause any damage to their surface. |
| 125 // TODO(eseckler): Make this the default heuristic once we can guarantee |
| 126 // observers to call DidFinishFrame() for every frame. |
| 127 all_active_child_surfaces_ready_to_draw_ = |
| 128 begin_frame_source_->AllObserversFinishedFrame(); |
| 129 } else { |
| 130 // TODO(mithro): Use hints from SetNeedsBeginFrames and SwapAborts. |
| 131 all_active_child_surfaces_ready_to_draw_ = base::STLIncludes( |
| 132 child_surface_ids_damaged_, child_surface_ids_to_expect_damage_from_); |
| 133 } |
| 114 } | 134 } |
| 115 | 135 |
| 116 StartObservingBeginFrames(); | 136 StartObservingBeginFrames(); |
| 117 ScheduleBeginFrameDeadline(); | 137 ScheduleBeginFrameDeadline(); |
| 118 } | 138 } |
| 119 | 139 |
| 120 void DisplayScheduler::OutputSurfaceLost() { | 140 void DisplayScheduler::OutputSurfaceLost() { |
| 121 TRACE_EVENT0("cc", "DisplayScheduler::OutputSurfaceLost"); | 141 TRACE_EVENT0("cc", "DisplayScheduler::OutputSurfaceLost"); |
| 122 output_surface_lost_ = true; | 142 output_surface_lost_ = true; |
| 123 ScheduleBeginFrameDeadline(); | 143 ScheduleBeginFrameDeadline(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 // synchronously trigger the previous deadline before progressing. | 201 // synchronously trigger the previous deadline before progressing. |
| 182 if (inside_begin_frame_deadline_interval_) { | 202 if (inside_begin_frame_deadline_interval_) { |
| 183 OnBeginFrameDeadline(); | 203 OnBeginFrameDeadline(); |
| 184 } | 204 } |
| 185 | 205 |
| 186 // Schedule the deadline. | 206 // Schedule the deadline. |
| 187 current_begin_frame_args_ = save_args; | 207 current_begin_frame_args_ = save_args; |
| 188 current_begin_frame_args_.deadline -= | 208 current_begin_frame_args_.deadline -= |
| 189 BeginFrameArgs::DefaultEstimatedParentDrawTime(); | 209 BeginFrameArgs::DefaultEstimatedParentDrawTime(); |
| 190 inside_begin_frame_deadline_interval_ = true; | 210 inside_begin_frame_deadline_interval_ = true; |
| 211 |
| 212 if (BeginFrameForcesDamage()) { |
| 213 // We know every surface that receives the BeginFrame will be damaged, so we |
| 214 // wait until all BeginFrameObservers have responded instead of waiting for |
| 215 // child_surface_ids_to_expect_damage_from_. |
| 216 expect_damage_from_root_surface_ = false; |
| 217 all_active_child_surfaces_ready_to_draw_ = |
| 218 begin_frame_source_->AllObserversFinishedFrame(); |
| 219 } |
| 220 |
| 191 ScheduleBeginFrameDeadline(); | 221 ScheduleBeginFrameDeadline(); |
| 192 | |
| 193 return true; | 222 return true; |
| 194 } | 223 } |
| 195 | 224 |
| 196 void DisplayScheduler::StartObservingBeginFrames() { | 225 void DisplayScheduler::StartObservingBeginFrames() { |
| 197 if (!observing_begin_frame_source_ && ShouldDraw()) { | 226 if (!observing_begin_frame_source_ && ShouldDraw()) { |
| 198 begin_frame_source_->AddObserver(this); | 227 // We don't want to wait for our own DidFinishFrame() when using |
| 228 // begin_frame_source_->AllObserversFinishedFrame(), so we add ourselves to |
| 229 // the target source directly. |
| 230 begin_frame_source_->GetTargetSource()->AddObserver(this); |
| 199 observing_begin_frame_source_ = true; | 231 observing_begin_frame_source_ = true; |
| 200 } | 232 } |
| 201 } | 233 } |
| 202 | 234 |
| 203 void DisplayScheduler::StopObservingBeginFrames() { | 235 void DisplayScheduler::StopObservingBeginFrames() { |
| 204 if (observing_begin_frame_source_) { | 236 if (observing_begin_frame_source_) { |
| 205 begin_frame_source_->RemoveObserver(this); | 237 begin_frame_source_->GetTargetSource()->RemoveObserver(this); |
| 206 observing_begin_frame_source_ = false; | 238 observing_begin_frame_source_ = false; |
| 207 | 239 |
| 208 // A missed BeginFrame may be queued, so drop that too if we're going to | 240 // A missed BeginFrame may be queued, so drop that too if we're going to |
| 209 // stop listening. | 241 // stop listening. |
| 210 missed_begin_frame_task_.Cancel(); | 242 missed_begin_frame_task_.Cancel(); |
| 211 } | 243 } |
| 212 } | 244 } |
| 213 | 245 |
| 214 bool DisplayScheduler::ShouldDraw() { | 246 bool DisplayScheduler::ShouldDraw() { |
| 215 // Note: When any of these cases becomes true, StartObservingBeginFrames must | 247 // Note: When any of these cases becomes true, StartObservingBeginFrames must |
| 216 // be called to ensure the draw will happen. | 248 // be called to ensure the draw will happen. |
| 217 return needs_draw_ && !output_surface_lost_ && visible_; | 249 return needs_draw_ && !output_surface_lost_ && visible_; |
| 218 } | 250 } |
| 219 | 251 |
| 252 bool DisplayScheduler::BeginFrameForcesDamage() const { |
| 253 return !current_begin_frame_args_.allow_latency_optimizations; |
| 254 } |
| 255 |
| 220 void DisplayScheduler::OnBeginFrameSourcePausedChanged(bool paused) { | 256 void DisplayScheduler::OnBeginFrameSourcePausedChanged(bool paused) { |
| 221 // BeginFrameSources used with DisplayScheduler do not make use of this | 257 // BeginFrameSources used with DisplayScheduler do not make use of this |
| 222 // feature. | 258 // feature. |
| 223 if (paused) | 259 if (paused) |
| 224 NOTIMPLEMENTED(); | 260 NOTIMPLEMENTED(); |
| 225 } | 261 } |
| 226 | 262 |
| 263 void DisplayScheduler::ObserverStatusChanged() { |
| 264 // If we're using the BeginFrameObservers to determine when all active |
| 265 // surfaces have been damaged, we may need to update the deadline. |
| 266 if (BeginFrameForcesDamage()) { |
| 267 all_active_child_surfaces_ready_to_draw_ = |
| 268 begin_frame_source_->AllObserversFinishedFrame(); |
| 269 ScheduleBeginFrameDeadline(); |
| 270 } |
| 271 } |
| 272 |
| 273 void DisplayScheduler::BeginFrameSourceSwapping(BeginFrameSource* new_source) { |
| 274 DCHECK(new_source); |
| 275 if (observing_begin_frame_source_) { |
| 276 begin_frame_source_->GetTargetSource()->RemoveObserver(this); |
| 277 new_source->AddObserver(this); |
| 278 } |
| 279 } |
| 280 |
| 227 base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { | 281 base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { |
| 228 if (output_surface_lost_) { | 282 if (output_surface_lost_) { |
| 229 TRACE_EVENT_INSTANT0("cc", "Lost output surface", TRACE_EVENT_SCOPE_THREAD); | 283 TRACE_EVENT_INSTANT0("cc", "Lost output surface", TRACE_EVENT_SCOPE_THREAD); |
| 230 return base::TimeTicks(); | 284 return base::TimeTicks(); |
| 231 } | 285 } |
| 232 | 286 |
| 233 if (pending_swaps_ >= max_pending_swaps_) { | 287 if (pending_swaps_ >= max_pending_swaps_) { |
| 234 TRACE_EVENT_INSTANT0("cc", "Swap throttled", TRACE_EVENT_SCOPE_THREAD); | 288 TRACE_EVENT_INSTANT0("cc", "Swap throttled", TRACE_EVENT_SCOPE_THREAD); |
| 235 return current_begin_frame_args_.frame_time + | 289 return current_begin_frame_args_.frame_time + |
| 236 current_begin_frame_args_.interval; | 290 current_begin_frame_args_.interval; |
| 237 } | 291 } |
| 238 | 292 |
| 239 if (!needs_draw_) { | 293 // Allow an immediate deadline even if there's no damage and we know that |
| 294 // no BeginFrameObservers are active. |
| 295 if (!needs_draw_ && |
| 296 !(BeginFrameForcesDamage() && all_active_child_surfaces_ready_to_draw_)) { |
| 240 TRACE_EVENT_INSTANT0("cc", "No damage yet", TRACE_EVENT_SCOPE_THREAD); | 297 TRACE_EVENT_INSTANT0("cc", "No damage yet", TRACE_EVENT_SCOPE_THREAD); |
| 241 return current_begin_frame_args_.frame_time + | 298 return current_begin_frame_args_.frame_time + |
| 242 current_begin_frame_args_.interval; | 299 current_begin_frame_args_.interval; |
| 243 } | 300 } |
| 244 | 301 |
| 245 if (root_surface_resources_locked_) { | 302 if (root_surface_resources_locked_) { |
| 246 TRACE_EVENT_INSTANT0("cc", "Root surface resources locked", | 303 TRACE_EVENT_INSTANT0("cc", "Root surface resources locked", |
| 247 TRACE_EVENT_SCOPE_THREAD); | 304 TRACE_EVENT_SCOPE_THREAD); |
| 248 return current_begin_frame_args_.frame_time + | 305 return current_begin_frame_args_.frame_time + |
| 249 current_begin_frame_args_.interval; | 306 current_begin_frame_args_.interval; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 344 expect_damage_from_root_surface_ = false; | 401 expect_damage_from_root_surface_ = false; |
| 345 | 402 |
| 346 StopObservingBeginFrames(); | 403 StopObservingBeginFrames(); |
| 347 } | 404 } |
| 348 } | 405 } |
| 349 | 406 |
| 350 void DisplayScheduler::OnBeginFrameDeadline() { | 407 void DisplayScheduler::OnBeginFrameDeadline() { |
| 351 TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline"); | 408 TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline"); |
| 352 | 409 |
| 353 AttemptDrawAndSwap(); | 410 AttemptDrawAndSwap(); |
| 354 begin_frame_source_->DidFinishFrame(this, 0); | 411 begin_frame_source_->GetTargetSource()->DidFinishFrame(this, 0); |
| 355 } | 412 } |
| 356 | 413 |
| 357 void DisplayScheduler::DidSwapBuffers() { | 414 void DisplayScheduler::DidSwapBuffers() { |
| 358 pending_swaps_++; | 415 pending_swaps_++; |
| 359 TRACE_EVENT_ASYNC_BEGIN1("cc", "DisplayScheduler:pending_swaps", this, | 416 TRACE_EVENT_ASYNC_BEGIN1("cc", "DisplayScheduler:pending_swaps", this, |
| 360 "pending_frames", pending_swaps_); | 417 "pending_frames", pending_swaps_); |
| 361 } | 418 } |
| 362 | 419 |
| 363 void DisplayScheduler::DidReceiveSwapBuffersAck() { | 420 void DisplayScheduler::DidReceiveSwapBuffersAck() { |
| 364 pending_swaps_--; | 421 pending_swaps_--; |
| 365 TRACE_EVENT_ASYNC_END1("cc", "DisplayScheduler:pending_swaps", this, | 422 TRACE_EVENT_ASYNC_END1("cc", "DisplayScheduler:pending_swaps", this, |
| 366 "pending_frames", pending_swaps_); | 423 "pending_frames", pending_swaps_); |
| 367 ScheduleBeginFrameDeadline(); | 424 ScheduleBeginFrameDeadline(); |
| 368 } | 425 } |
| 369 | 426 |
| 370 } // namespace cc | 427 } // namespace cc |
| OLD | NEW |