Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: cc/surfaces/display_scheduler.cc

Issue 1138563002: Add DisplayScheduler for Surfaces (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@rendererLatencyRecoveryHeuristic
Patch Set: rebase Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/surfaces/display_scheduler.h ('k') | cc/surfaces/display_scheduler_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "cc/surfaces/display_scheduler.h"
6
7 #include <vector>
8
9 #include "base/stl_util.h"
10 #include "base/trace_event/trace_event.h"
11 #include "cc/output/output_surface.h"
12 #include "ui/gfx/frame_time.h"
13
14 namespace cc {
15
16 DisplayScheduler::DisplayScheduler(
17 DisplaySchedulerClient* client,
18 BeginFrameSource* begin_frame_source,
19 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
20 int max_pending_swaps)
21 : client_(client),
22 begin_frame_source_(begin_frame_source),
23 task_runner_(task_runner),
24 output_surface_lost_(false),
25 root_surface_resources_locked_(true),
26 inside_begin_frame_deadline_interval_(false),
27 needs_draw_(false),
28 entire_display_damaged_(false),
29 all_active_child_surfaces_ready_to_draw_(false),
30 pending_swaps_(0),
31 max_pending_swaps_(max_pending_swaps),
32 root_surface_damaged_(false),
33 expect_damage_from_root_surface_(false),
34 weak_ptr_factory_(this) {
35 begin_frame_source_->AddObserver(this);
36 begin_frame_deadline_closure_ = base::Bind(
37 &DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr());
38 }
39
40 DisplayScheduler::~DisplayScheduler() {
41 begin_frame_source_->RemoveObserver(this);
42 }
43
44 // If we try to draw when the root surface resources are locked, the
45 // draw will fail.
46 void DisplayScheduler::SetRootSurfaceResourcesLocked(bool locked) {
47 root_surface_resources_locked_ = locked;
48 ScheduleBeginFrameDeadline();
49 }
50
51 // Notification that there was a resize or the root surface changed and
52 // that we should just draw immediately.
53 void DisplayScheduler::EntireDisplayDamaged(SurfaceId root_surface_id) {
54 TRACE_EVENT0("cc", "DisplayScheduler::EntireDisplayDamaged");
55 needs_draw_ = true;
56 entire_display_damaged_ = true;
57 root_surface_id_ = root_surface_id;
58
59 begin_frame_source_->SetNeedsBeginFrames(!output_surface_lost_);
60 ScheduleBeginFrameDeadline();
61 }
62
63 // Indicates that there was damage to one of the surfaces.
64 // Has some logic to wait for multiple active surfaces before
65 // triggering the deadline.
66 void DisplayScheduler::SurfaceDamaged(SurfaceId surface_id) {
67 TRACE_EVENT1("cc", "DisplayScheduler::SurfaceDamaged", "surface_id",
68 surface_id.id);
69
70 needs_draw_ = true;
71
72 if (surface_id == root_surface_id_) {
73 root_surface_damaged_ = true;
74 } else {
75 child_surface_ids_damaged_.insert(surface_id);
76
77 // TODO(mithro): Use hints from SetNeedsBeginFrames and SwapAborts.
78 all_active_child_surfaces_ready_to_draw_ = base::STLIncludes(
79 child_surface_ids_damaged_, child_surface_ids_to_expect_damage_from_);
80 }
81
82 begin_frame_source_->SetNeedsBeginFrames(!output_surface_lost_);
83 ScheduleBeginFrameDeadline();
84 }
85
86 void DisplayScheduler::OutputSurfaceLost() {
87 TRACE_EVENT0("cc", "DisplayScheduler::OutputSurfaceLost");
88 output_surface_lost_ = true;
89 begin_frame_source_->SetNeedsBeginFrames(false);
90 ScheduleBeginFrameDeadline();
91 }
92
93 void DisplayScheduler::DrawAndSwap() {
94 TRACE_EVENT0("cc", "DisplayScheduler::DrawAndSwap");
95 DCHECK_LT(pending_swaps_, max_pending_swaps_);
96 DCHECK(!output_surface_lost_);
97
98 bool success = client_->DrawAndSwap();
99 if (!success)
100 return;
101
102 needs_draw_ = false;
103 entire_display_damaged_ = false;
104 all_active_child_surfaces_ready_to_draw_ = false;
105
106 expect_damage_from_root_surface_ = root_surface_damaged_;
107 root_surface_damaged_ = false;
108
109 child_surface_ids_to_expect_damage_from_ =
110 base::STLSetIntersection<std::vector<SurfaceId>>(
111 child_surface_ids_damaged_, child_surface_ids_damaged_prev_);
112
113 child_surface_ids_damaged_prev_.swap(child_surface_ids_damaged_);
114 child_surface_ids_damaged_.clear();
115 }
116
117 bool DisplayScheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) {
118 base::TimeTicks now = gfx::FrameTime::Now();
119 TRACE_EVENT2("cc", "DisplayScheduler::BeginFrame", "args", args.AsValue(),
120 "now", now);
121
122 // Only service missed BeginFrames if they haven't already expired.
123 base::TimeTicks adjusted_deadline =
124 args.deadline - BeginFrameArgs::DefaultEstimatedParentDrawTime();
125 if (args.type == BeginFrameArgs::MISSED && now > adjusted_deadline)
126 return false;
127
128 // If we get another BeginFrame before the previous deadline,
129 // synchronously trigger the previous deadline before progressing.
130 if (inside_begin_frame_deadline_interval_) {
131 OnBeginFrameDeadline();
132 }
133
134 // Schedule the deadline.
135 current_begin_frame_args_ = args;
136 current_begin_frame_args_.deadline = adjusted_deadline;
137 inside_begin_frame_deadline_interval_ = true;
138 ScheduleBeginFrameDeadline();
139
140 return true;
141 }
142
143 base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() {
144 if (output_surface_lost_) {
145 TRACE_EVENT_INSTANT0("cc", "Lost output surface", TRACE_EVENT_SCOPE_THREAD);
146 return base::TimeTicks();
147 }
148
149 if (pending_swaps_ >= max_pending_swaps_) {
150 TRACE_EVENT_INSTANT0("cc", "Swap throttled", TRACE_EVENT_SCOPE_THREAD);
151 return base::TimeTicks();
152 }
153
154 if (!needs_draw_) {
155 TRACE_EVENT_INSTANT0("cc", "No damage yet", TRACE_EVENT_SCOPE_THREAD);
156 return current_begin_frame_args_.frame_time +
157 current_begin_frame_args_.interval;
158 }
159
160 if (root_surface_resources_locked_) {
161 TRACE_EVENT_INSTANT0("cc", "Root surface resources locked",
162 TRACE_EVENT_SCOPE_THREAD);
163 return current_begin_frame_args_.frame_time +
164 current_begin_frame_args_.interval;
165 }
166
167 // TODO(mithro): Be smarter about resize deadlines.
168 if (entire_display_damaged_) {
169 TRACE_EVENT_INSTANT0("cc", "Entire display damaged",
170 TRACE_EVENT_SCOPE_THREAD);
171 return base::TimeTicks();
172 }
173
174 bool root_ready_to_draw =
175 !expect_damage_from_root_surface_ || root_surface_damaged_;
176
177 if (all_active_child_surfaces_ready_to_draw_ && root_ready_to_draw) {
178 TRACE_EVENT_INSTANT0("cc", "All active surfaces ready",
179 TRACE_EVENT_SCOPE_THREAD);
180 return base::TimeTicks();
181 }
182
183 // Use an earlier deadline if we are only waiting for the root surface
184 // in case our expect_damage_from_root_surface heuristic is incorrect.
185 // TODO(mithro): Replace this with SetNeedsBeginFrame and SwapAbort
186 // logic.
187 if (all_active_child_surfaces_ready_to_draw_ &&
188 expect_damage_from_root_surface_) {
189 TRACE_EVENT_INSTANT0("cc", "Waiting for damage from root surface",
190 TRACE_EVENT_SCOPE_THREAD);
191 // This adjusts the deadline by DefaultEstimatedParentDrawTime for
192 // a second time. The first one represented the Surfaces draw to display
193 // latency. This one represents root surface commit+raster+draw latency.
194 // We treat the root surface differently since it lives on the same thread
195 // as Surfaces and waiting for it too long may push out the Surfaces draw.
196 // If we also assume the root surface is fast to start a commit after the
197 // beginning of a frame, it'll have a chance to lock its resources, which
198 // will cause us to wait for it to unlock its resources above.
199 // TODO(mithro): Replace hard coded estimates.
200 return current_begin_frame_args_.deadline -
201 BeginFrameArgs::DefaultEstimatedParentDrawTime();
202 }
203
204 TRACE_EVENT_INSTANT0("cc", "More damage expected soon",
205 TRACE_EVENT_SCOPE_THREAD);
206 return current_begin_frame_args_.deadline;
207 }
208
209 void DisplayScheduler::ScheduleBeginFrameDeadline() {
210 TRACE_EVENT0("cc", "DisplayScheduler::ScheduleBeginFrameDeadline");
211
212 // We need to wait for the next BeginFrame before scheduling a deadline.
213 if (!inside_begin_frame_deadline_interval_) {
214 TRACE_EVENT_INSTANT0("cc", "Waiting for next BeginFrame",
215 TRACE_EVENT_SCOPE_THREAD);
216 DCHECK(begin_frame_deadline_task_.IsCancelled());
217 return;
218 }
219
220 // Determine the deadline we want to use.
221 base::TimeTicks desired_deadline = DesiredBeginFrameDeadlineTime();
222
223 // Avoid re-scheduling the deadline if it's already correctly scheduled.
224 if (!begin_frame_deadline_task_.IsCancelled() &&
225 desired_deadline == begin_frame_deadline_task_time_) {
226 TRACE_EVENT_INSTANT0("cc", "Using existing deadline",
227 TRACE_EVENT_SCOPE_THREAD);
228 return;
229 }
230
231 // Schedule the deadline.
232 begin_frame_deadline_task_time_ = desired_deadline;
233 begin_frame_deadline_task_.Cancel();
234 begin_frame_deadline_task_.Reset(begin_frame_deadline_closure_);
235
236 base::TimeDelta delta =
237 std::max(base::TimeDelta(), desired_deadline - gfx::FrameTime::Now());
238 task_runner_->PostDelayedTask(FROM_HERE,
239 begin_frame_deadline_task_.callback(), delta);
240 TRACE_EVENT2("cc", "Using new deadline", "delta", delta.ToInternalValue(),
241 "desired_deadline", desired_deadline);
242 }
243
244 void DisplayScheduler::OnBeginFrameDeadline() {
245 TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline");
246 inside_begin_frame_deadline_interval_ = false;
247 begin_frame_deadline_task_.Cancel();
248 begin_frame_deadline_task_time_ = base::TimeTicks();
249
250 if (needs_draw_ && !output_surface_lost_) {
251 if (pending_swaps_ < max_pending_swaps_ && !root_surface_resources_locked_)
252 DrawAndSwap();
253 } else {
254 begin_frame_source_->SetNeedsBeginFrames(false);
255 }
256
257 begin_frame_source_->DidFinishFrame(0);
258 }
259
260 void DisplayScheduler::DidSwapBuffers() {
261 pending_swaps_++;
262 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffers", "pending_frames",
263 pending_swaps_);
264 }
265
266 void DisplayScheduler::DidSwapBuffersComplete() {
267 pending_swaps_--;
268 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffersComplete",
269 "pending_frames", pending_swaps_);
270 ScheduleBeginFrameDeadline();
271 }
272
273 } // namespace cc
OLDNEW
« no previous file with comments | « cc/surfaces/display_scheduler.h ('k') | cc/surfaces/display_scheduler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698