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

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

Issue 1012853003: Add DisplayScheduler for Surfaces (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: DisplaySchedulerClient in preparation of unittests Created 5 years, 8 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
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 OutputSurface* output_surface,
19 int max_pending_swaps,
20 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
21 : client_(client),
22 output_surface_(output_surface),
23 task_runner_(task_runner),
24 vsync_observer_(nullptr),
25 output_surface_lost_(false),
26 inside_begin_frame_deadline_interval_(false),
27 resources_locked_by_browser_(true),
28 needs_draw_(false),
29 entire_display_damaged_(false),
30 all_active_surfaces_ready_to_draw_(false),
31 pending_swaps_(0),
32 max_pending_swaps_(max_pending_swaps),
33 weak_ptr_factory_(this) {
34 auto synthtic_begin_frame_source = SyntheticBeginFrameSource::Create(
35 task_runner_.get(), gfx::FrameTime::Now(),
36 BeginFrameArgs::DefaultInterval());
37 vsync_observer_ = synthtic_begin_frame_source.get();
38 begin_frame_source_ = synthtic_begin_frame_source.Pass();
39 begin_frame_source_->AddObserver(this);
40
41 begin_impl_frame_deadline_closure_ = base::Bind(
42 &DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr());
43 }
44
45 DisplayScheduler::~DisplayScheduler() {
46 }
47
48 void DisplayScheduler::SetAuthoritativeVSyncInterval(
brianderson 2015/04/07 02:32:19 Got rid of this for now. We can add it when it's a
49 const base::TimeDelta& interval) {
50 authoritative_vsync_interval_ = interval;
51 if (vsync_observer_)
52 vsync_observer_->OnUpdateVSyncParameters(last_vsync_timebase_, interval);
53 }
54
55 void DisplayScheduler::CommitVSyncParameters(base::TimeTicks timebase,
56 base::TimeDelta interval) {
57 TRACE_EVENT2("cc", "DisplayScheduler::CommitVSyncParameters", "timebase",
58 (timebase - base::TimeTicks()).InSecondsF(), "interval",
59 interval.InSecondsF());
60
61 if (authoritative_vsync_interval_ != base::TimeDelta()) {
62 interval = authoritative_vsync_interval_;
63 } else if (interval == base::TimeDelta()) {
64 // TODO(brianderson): We should not be receiving 0 intervals.
65 interval = BeginFrameArgs::DefaultInterval();
66 }
67
68 last_vsync_timebase_ = timebase;
69
70 if (vsync_observer_)
71 vsync_observer_->OnUpdateVSyncParameters(timebase, interval);
72 }
73
74 // If we try to draw when the Browser has locked it's resources, the
75 // draw will fail.
76 void DisplayScheduler::SetResourcesLockedByBrowser(bool locked) {
77 resources_locked_by_browser_ = locked;
78 }
79
80 // Notification that there was a resize or the root surface changed and
81 // that we should just draw immediately.
82 void DisplayScheduler::EntireDisplayDamaged() {
83 TRACE_EVENT0("cc", "DisplayScheduler::EntireDisplayDamaged");
84 needs_draw_ = true;
85 entire_display_damaged_ = true;
86 }
87
88 // Indicates that there was damage to one of the surfaces.
89 // Has some logic to wait for multiple active surfaces before
90 // triggering the deadline.
91 void DisplayScheduler::SurfaceDamaged(SurfaceId surface_id) {
92 TRACE_EVENT1("cc", "DisplayScheduler::SurfaceDamaged", "surface_id",
93 surface_id.id);
94
95 needs_draw_ = true;
96
97 surface_ids_damaged_.insert(surface_id);
98
99 // TODO(mithro): Use hints from SetNeedsBeginFrames.
100 all_active_surfaces_ready_to_draw_ = base::STLIncludes(
101 surface_ids_damaged_, surface_ids_to_expect_damage_from_);
102
103 begin_frame_source_->SetNeedsBeginFrames(!output_surface_lost_);
104 ScheduleBeginFrameDeadline();
105 }
106
107 void DisplayScheduler::OutputSurfaceLost() {
108 TRACE_EVENT0("cc", "DisplayScheduler::OutputSurfaceLost");
109 output_surface_lost_ = true;
110 begin_frame_source_->SetNeedsBeginFrames(false);
111 ScheduleBeginFrameDeadline();
112 }
113
114 void DisplayScheduler::Draw() {
115 TRACE_EVENT0("cc", "DisplayScheduler::Draw");
116 DCHECK_LT(pending_swaps_, max_pending_swaps_);
117 DCHECK(!output_surface_lost_);
118
119 needs_draw_ = false;
120 entire_display_damaged_ = false;
121 all_active_surfaces_ready_to_draw_ = false;
122
123 client_->Draw();
124
125 surface_ids_to_expect_damage_from_ =
126 base::STLSetUnion<std::vector<SurfaceId>>(surface_ids_damaged_,
127 surface_ids_damaged_prev_);
128
129 surface_ids_damaged_prev_.swap(surface_ids_damaged_);
130 surface_ids_damaged_.clear();
131 }
132
133 bool DisplayScheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) {
134 TRACE_EVENT1("cc", "DisplayScheduler::BeginFrame", "args", args.AsValue());
135
136 // If we get another BeginFrame before the previous deadline,
137 // synchronously trigger the previous deadline before progressing.
138 if (inside_begin_frame_deadline_interval_) {
139 OnBeginFrameDeadline();
140 }
141
142 // Schedule the deadline.
143 current_begin_frame_args_ = args;
144 current_begin_frame_args_.deadline -=
145 BeginFrameArgs::DefaultEstimatedParentDrawTime();
146 inside_begin_frame_deadline_interval_ = true;
147 ScheduleBeginFrameDeadline();
148
149 return true;
150 }
151
152 base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() {
153 if (output_surface_lost_) {
154 TRACE_EVENT_INSTANT0("cc", "Lost output surface", TRACE_EVENT_SCOPE_THREAD);
155 return base::TimeTicks();
156 }
157
158 if (pending_swaps_ >= max_pending_swaps_) {
159 TRACE_EVENT_INSTANT0("cc", "Swap throttled", TRACE_EVENT_SCOPE_THREAD);
160 return current_begin_frame_args_.frame_time +
161 current_begin_frame_args_.interval;
162 }
163
164 if (resources_locked_by_browser_) {
165 TRACE_EVENT_INSTANT0("cc", "Resources locked by Browser",
166 TRACE_EVENT_SCOPE_THREAD);
167 return current_begin_frame_args_.frame_time +
168 current_begin_frame_args_.interval;
169 }
170
171 if (entire_display_damaged_) {
172 TRACE_EVENT_INSTANT0("cc", "Entire display damaged",
173 TRACE_EVENT_SCOPE_THREAD);
174 return base::TimeTicks();
175 }
176
177 if (all_active_surfaces_ready_to_draw_) {
178 TRACE_EVENT_INSTANT0("cc", "Active surfaces ready",
179 TRACE_EVENT_SCOPE_THREAD);
180 return base::TimeTicks();
181 }
182
183 if (needs_draw_) {
184 TRACE_EVENT_INSTANT0("cc", "More damage expected soon",
185 TRACE_EVENT_SCOPE_THREAD);
186 return current_begin_frame_args_.deadline;
187 }
188
189 TRACE_EVENT_INSTANT0("cc", "No damage yet", TRACE_EVENT_SCOPE_THREAD);
190 return current_begin_frame_args_.frame_time +
191 current_begin_frame_args_.interval;
192 }
193
194 void DisplayScheduler::ScheduleBeginFrameDeadline() {
195 TRACE_EVENT0("cc", "DisplayScheduler::ScheduleBeginFrameDeadline");
196
197 // We need to wait for the next BeginFrame before scheduling a deadline.
198 if (!inside_begin_frame_deadline_interval_) {
199 TRACE_EVENT_INSTANT0("cc", "Waiting for next BeginFrame",
200 TRACE_EVENT_SCOPE_THREAD);
201 DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
202 return;
203 }
204
205 // Determine the deadline we want to use.
206 base::TimeTicks desired_deadline = DesiredBeginFrameDeadlineTime();
207
208 // Avoid re-scheduling the deadline if it's already correctly scheduled.
209 if (!begin_impl_frame_deadline_task_.IsCancelled() &&
210 desired_deadline == begin_impl_frame_deadline_task_time_)
211 return;
212
213 // Schedule the deadline.
214 begin_impl_frame_deadline_task_time_ = desired_deadline;
215 begin_impl_frame_deadline_task_.Cancel();
216 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
217
218 base::TimeDelta delta =
219 std::max(base::TimeDelta(), desired_deadline - base::TimeTicks::Now());
220 task_runner_->PostDelayedTask(
221 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
222 }
223
224 void DisplayScheduler::OnBeginFrameDeadline() {
225 TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline");
226 begin_impl_frame_deadline_task_.Cancel();
227 begin_impl_frame_deadline_task_time_ = base::TimeTicks();
228
229 if (needs_draw_ && !output_surface_lost_) {
230 if (pending_swaps_ < max_pending_swaps_)
231 Draw();
232 } else {
233 begin_frame_source_->SetNeedsBeginFrames(false);
234 }
235
236 inside_begin_frame_deadline_interval_ = false;
237 begin_frame_source_->DidFinishFrame(0);
238 }
239
240 void DisplayScheduler::DidSwapBuffers() {
241 pending_swaps_++;
242 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffers", "pending_frames",
243 pending_swaps_);
244 }
245
246 void DisplayScheduler::DidSwapBuffersComplete() {
247 pending_swaps_--;
248 TRACE_EVENT1("cc", "DisplayScheduler::DidSwapBuffersComplete",
249 "pending_frames", pending_swaps_);
250 ScheduleBeginFrameDeadline();
251 }
252
253 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698