Vectorize website settings icons in omnibox
[chromium-blink-merge.git] / cc / surfaces / display_scheduler.cc
blob033632ec9ca4919b3ce22e42b739213e6c21ba60
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
3 // found in the LICENSE file.
5 #include "cc/surfaces/display_scheduler.h"
7 #include <vector>
9 #include "base/stl_util.h"
10 #include "base/trace_event/trace_event.h"
11 #include "cc/output/output_surface.h"
13 namespace cc {
15 DisplayScheduler::DisplayScheduler(DisplaySchedulerClient* client,
16 BeginFrameSource* begin_frame_source,
17 base::SingleThreadTaskRunner* task_runner,
18 int max_pending_swaps)
19 : client_(client),
20 begin_frame_source_(begin_frame_source),
21 task_runner_(task_runner),
22 output_surface_lost_(false),
23 root_surface_resources_locked_(true),
24 inside_begin_frame_deadline_interval_(false),
25 needs_draw_(false),
26 expecting_root_surface_damage_because_of_resize_(false),
27 all_active_child_surfaces_ready_to_draw_(false),
28 pending_swaps_(0),
29 max_pending_swaps_(max_pending_swaps),
30 root_surface_damaged_(false),
31 expect_damage_from_root_surface_(false),
32 weak_ptr_factory_(this) {
33 begin_frame_source_->AddObserver(this);
34 begin_frame_deadline_closure_ = base::Bind(
35 &DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr());
38 DisplayScheduler::~DisplayScheduler() {
39 begin_frame_source_->RemoveObserver(this);
42 // If we try to draw when the root surface resources are locked, the
43 // draw will fail.
44 void DisplayScheduler::SetRootSurfaceResourcesLocked(bool locked) {
45 TRACE_EVENT1("cc", "DisplayScheduler::SetRootSurfaceResourcesLocked",
46 "locked", locked);
47 root_surface_resources_locked_ = locked;
48 ScheduleBeginFrameDeadline();
51 // This is used to force an immediate swap before a resize.
52 void DisplayScheduler::ForceImmediateSwapIfPossible() {
53 TRACE_EVENT0("cc", "DisplayScheduler::ForceImmediateSwapIfPossible");
54 bool in_begin = inside_begin_frame_deadline_interval_;
55 AttemptDrawAndSwap();
56 if (in_begin)
57 begin_frame_source_->DidFinishFrame(0);
60 void DisplayScheduler::DisplayResized() {
61 expecting_root_surface_damage_because_of_resize_ = true;
62 expect_damage_from_root_surface_ = true;
63 needs_draw_ = true;
64 ScheduleBeginFrameDeadline();
67 // Notification that there was a resize or the root surface changed and
68 // that we should just draw immediately.
69 void DisplayScheduler::SetNewRootSurface(SurfaceId root_surface_id) {
70 TRACE_EVENT0("cc", "DisplayScheduler::SetNewRootSurface");
71 root_surface_id_ = root_surface_id;
72 SurfaceDamaged(root_surface_id);
75 // Indicates that there was damage to one of the surfaces.
76 // Has some logic to wait for multiple active surfaces before
77 // triggering the deadline.
78 void DisplayScheduler::SurfaceDamaged(SurfaceId surface_id) {
79 TRACE_EVENT1("cc", "DisplayScheduler::SurfaceDamaged", "surface_id",
80 surface_id.id);
82 needs_draw_ = true;
84 if (surface_id == root_surface_id_) {
85 root_surface_damaged_ = true;
86 expecting_root_surface_damage_because_of_resize_ = false;
87 } else {
88 child_surface_ids_damaged_.insert(surface_id);
90 // TODO(mithro): Use hints from SetNeedsBeginFrames and SwapAborts.
91 all_active_child_surfaces_ready_to_draw_ = base::STLIncludes(
92 child_surface_ids_damaged_, child_surface_ids_to_expect_damage_from_);
95 begin_frame_source_->SetNeedsBeginFrames(!output_surface_lost_);
96 ScheduleBeginFrameDeadline();
99 void DisplayScheduler::OutputSurfaceLost() {
100 TRACE_EVENT0("cc", "DisplayScheduler::OutputSurfaceLost");
101 output_surface_lost_ = true;
102 begin_frame_source_->SetNeedsBeginFrames(false);
103 ScheduleBeginFrameDeadline();
106 void DisplayScheduler::DrawAndSwap() {
107 TRACE_EVENT0("cc", "DisplayScheduler::DrawAndSwap");
108 DCHECK_LT(pending_swaps_, max_pending_swaps_);
109 DCHECK(!output_surface_lost_);
111 bool success = client_->DrawAndSwap();
112 if (!success)
113 return;
115 child_surface_ids_to_expect_damage_from_ =
116 base::STLSetIntersection<std::vector<SurfaceId>>(
117 child_surface_ids_damaged_, child_surface_ids_damaged_prev_);
119 child_surface_ids_damaged_prev_.swap(child_surface_ids_damaged_);
120 child_surface_ids_damaged_.clear();
122 needs_draw_ = false;
123 all_active_child_surfaces_ready_to_draw_ =
124 child_surface_ids_to_expect_damage_from_.empty();
126 expect_damage_from_root_surface_ = root_surface_damaged_;
127 root_surface_damaged_ = false;
130 bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) {
131 base::TimeTicks now = base::TimeTicks::Now();
132 TRACE_EVENT2("cc", "DisplayScheduler::BeginFrame", "args", args.AsValue(),
133 "now", now);
135 // If we get another BeginFrame before the previous deadline,
136 // synchronously trigger the previous deadline before progressing.
137 if (inside_begin_frame_deadline_interval_) {
138 OnBeginFrameDeadline();
141 // Schedule the deadline.
142 current_begin_frame_args_ = args;
143 current_begin_frame_args_.deadline -=
144 BeginFrameArgs::DefaultEstimatedParentDrawTime();
145 inside_begin_frame_deadline_interval_ = true;
146 ScheduleBeginFrameDeadline();
148 return true;
151 base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() {
152 if (output_surface_lost_) {
153 TRACE_EVENT_INSTANT0("cc", "Lost output surface", TRACE_EVENT_SCOPE_THREAD);
154 return base::TimeTicks();
157 if (pending_swaps_ >= max_pending_swaps_) {
158 TRACE_EVENT_INSTANT0("cc", "Swap throttled", TRACE_EVENT_SCOPE_THREAD);
159 return current_begin_frame_args_.frame_time +
160 current_begin_frame_args_.interval;
163 if (!needs_draw_) {
164 TRACE_EVENT_INSTANT0("cc", "No damage yet", TRACE_EVENT_SCOPE_THREAD);
165 return current_begin_frame_args_.frame_time +
166 current_begin_frame_args_.interval;
169 if (root_surface_resources_locked_) {
170 TRACE_EVENT_INSTANT0("cc", "Root surface resources locked",
171 TRACE_EVENT_SCOPE_THREAD);
172 return current_begin_frame_args_.frame_time +
173 current_begin_frame_args_.interval;
176 bool root_ready_to_draw =
177 !expect_damage_from_root_surface_ || root_surface_damaged_;
179 if (all_active_child_surfaces_ready_to_draw_ && root_ready_to_draw) {
180 TRACE_EVENT_INSTANT0("cc", "All active surfaces ready",
181 TRACE_EVENT_SCOPE_THREAD);
182 return base::TimeTicks();
185 // TODO(mithro): Be smarter about resize deadlines.
186 if (expecting_root_surface_damage_because_of_resize_) {
187 TRACE_EVENT_INSTANT0("cc", "Entire display damaged",
188 TRACE_EVENT_SCOPE_THREAD);
189 return current_begin_frame_args_.frame_time +
190 current_begin_frame_args_.interval;
193 // Use an earlier deadline if we are only waiting for the root surface
194 // in case our expect_damage_from_root_surface heuristic is incorrect.
195 // TODO(mithro): Replace this with SetNeedsBeginFrame and SwapAbort
196 // logic.
197 if (all_active_child_surfaces_ready_to_draw_ &&
198 expect_damage_from_root_surface_) {
199 TRACE_EVENT_INSTANT0("cc", "Waiting for damage from root surface",
200 TRACE_EVENT_SCOPE_THREAD);
201 // This adjusts the deadline by DefaultEstimatedParentDrawTime for
202 // a second time. The first one represented the Surfaces draw to display
203 // latency. This one represents root surface commit+raster+draw latency.
204 // We treat the root surface differently since it lives on the same thread
205 // as Surfaces and waiting for it too long may push out the Surfaces draw.
206 // If we also assume the root surface is fast to start a commit after the
207 // beginning of a frame, it'll have a chance to lock its resources, which
208 // will cause us to wait for it to unlock its resources above.
209 // TODO(mithro): Replace hard coded estimates.
210 return current_begin_frame_args_.deadline -
211 BeginFrameArgs::DefaultEstimatedParentDrawTime();
214 TRACE_EVENT_INSTANT0("cc", "More damage expected soon",
215 TRACE_EVENT_SCOPE_THREAD);
216 return current_begin_frame_args_.deadline;
219 void DisplayScheduler::ScheduleBeginFrameDeadline() {
220 TRACE_EVENT0("cc", "DisplayScheduler::ScheduleBeginFrameDeadline");
222 // We need to wait for the next BeginFrame before scheduling a deadline.
223 if (!inside_begin_frame_deadline_interval_) {
224 TRACE_EVENT_INSTANT0("cc", "Waiting for next BeginFrame",
225 TRACE_EVENT_SCOPE_THREAD);
226 DCHECK(begin_frame_deadline_task_.IsCancelled());
227 return;
230 // Determine the deadline we want to use.
231 base::TimeTicks desired_deadline = DesiredBeginFrameDeadlineTime();
233 // Avoid re-scheduling the deadline if it's already correctly scheduled.
234 if (!begin_frame_deadline_task_.IsCancelled() &&
235 desired_deadline == begin_frame_deadline_task_time_) {
236 TRACE_EVENT_INSTANT0("cc", "Using existing deadline",
237 TRACE_EVENT_SCOPE_THREAD);
238 return;
241 // Schedule the deadline.
242 begin_frame_deadline_task_time_ = desired_deadline;
243 begin_frame_deadline_task_.Cancel();
244 begin_frame_deadline_task_.Reset(begin_frame_deadline_closure_);
246 base::TimeDelta delta =
247 std::max(base::TimeDelta(), desired_deadline - base::TimeTicks::Now());
248 task_runner_->PostDelayedTask(FROM_HERE,
249 begin_frame_deadline_task_.callback(), delta);
250 TRACE_EVENT2("cc", "Using new deadline", "delta", delta.ToInternalValue(),
251 "desired_deadline", desired_deadline);
254 void DisplayScheduler::AttemptDrawAndSwap() {
255 inside_begin_frame_deadline_interval_ = false;
256 begin_frame_deadline_task_.Cancel();
257 begin_frame_deadline_task_time_ = base::TimeTicks();
259 if (needs_draw_ && !output_surface_lost_) {
260 if (pending_swaps_ < max_pending_swaps_ && !root_surface_resources_locked_)
261 DrawAndSwap();
262 } else {
263 // We are going idle, so reset expectations.
264 child_surface_ids_to_expect_damage_from_.clear();
265 child_surface_ids_damaged_prev_.clear();
266 child_surface_ids_damaged_.clear();
267 all_active_child_surfaces_ready_to_draw_ = true;
268 expect_damage_from_root_surface_ = false;
270 begin_frame_source_->SetNeedsBeginFrames(false);
274 void DisplayScheduler::OnBeginFrameDeadline() {
275 TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline");
277 AttemptDrawAndSwap();
278 begin_frame_source_->DidFinishFrame(0);
281 void DisplayScheduler::DidSwapBuffers() {
282 pending_swaps_++;
283 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffers", "pending_frames",
284 pending_swaps_);
287 void DisplayScheduler::DidSwapBuffersComplete() {
288 pending_swaps_--;
289 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffersComplete",
290 "pending_frames", pending_swaps_);
291 ScheduleBeginFrameDeadline();
294 } // namespace cc