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

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

Powered by Google App Engine
This is Rietveld 408576698