Add signalSyncPoint to the WebGraphicsContext3D command buffer impls.
[chromium-blink-merge.git] / cc / scheduler / scheduler_state_machine.cc
blobc55631d9122ce770f667bd809b153e5660909447
1 // Copyright 2011 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/scheduler/scheduler_state_machine.h"
7 #include "base/logging.h"
8 #include "base/stringprintf.h"
10 namespace cc {
12 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
13 : settings_(settings),
14 commit_state_(COMMIT_STATE_IDLE),
15 current_frame_number_(0),
16 last_frame_number_where_draw_was_called_(-1),
17 last_frame_number_where_tree_activation_attempted_(-1),
18 last_frame_number_where_check_for_completed_tile_uploads_called_(-1),
19 consecutive_failed_draws_(0),
20 maximum_number_of_failed_draws_before_draw_is_forced_(3),
21 needs_redraw_(false),
22 swap_used_incomplete_tile_(false),
23 needs_forced_redraw_(false),
24 needs_forced_redraw_after_next_commit_(false),
25 needs_commit_(false),
26 needs_forced_commit_(false),
27 expect_immediate_begin_frame_(false),
28 main_thread_needs_layer_textures_(false),
29 inside_vsync_(false),
30 visible_(false),
31 can_begin_frame_(false),
32 can_draw_(false),
33 has_pending_tree_(false),
34 draw_if_possible_failed_(false),
35 texture_state_(LAYER_TEXTURE_STATE_UNLOCKED),
36 output_surface_state_(OUTPUT_SURFACE_ACTIVE) {}
38 std::string SchedulerStateMachine::ToString() {
39 std::string str;
40 base::StringAppendF(&str,
41 "settings_.impl_side_painting = %d; ",
42 settings_.impl_side_painting);
43 base::StringAppendF(&str, "commit_state_ = %d; ", commit_state_);
44 base::StringAppendF(
45 &str, "current_frame_number_ = %d; ", current_frame_number_);
46 base::StringAppendF(&str,
47 "last_frame_number_where_draw_was_called_ = %d; ",
48 last_frame_number_where_draw_was_called_);
49 base::StringAppendF(
50 &str,
51 "last_frame_number_where_tree_activation_attempted_ = %d; ",
52 last_frame_number_where_tree_activation_attempted_);
53 base::StringAppendF(
54 &str,
55 "last_frame_number_where_check_for_completed_tile_uploads_called_ = %d; ",
56 last_frame_number_where_check_for_completed_tile_uploads_called_);
57 base::StringAppendF(
58 &str, "consecutive_failed_draws_ = %d; ", consecutive_failed_draws_);
59 base::StringAppendF(
60 &str,
61 "maximum_number_of_failed_draws_before_draw_is_forced_ = %d; ",
62 maximum_number_of_failed_draws_before_draw_is_forced_);
63 base::StringAppendF(&str, "needs_redraw_ = %d; ", needs_redraw_);
64 base::StringAppendF(
65 &str, "swap_used_incomplete_tile_ = %d; ", swap_used_incomplete_tile_);
66 base::StringAppendF(
67 &str, "needs_forced_redraw_ = %d; ", needs_forced_redraw_);
68 base::StringAppendF(&str,
69 "needs_forced_redraw_after_next_commit_ = %d; ",
70 needs_forced_redraw_after_next_commit_);
71 base::StringAppendF(&str, "needs_commit_ = %d; ", needs_commit_);
72 base::StringAppendF(
73 &str, "needs_forced_commit_ = %d; ", needs_forced_commit_);
74 base::StringAppendF(&str,
75 "expect_immediate_begin_frame_ = %d; ",
76 expect_immediate_begin_frame_);
77 base::StringAppendF(&str,
78 "main_thread_needs_layer_textures_ = %d; ",
79 main_thread_needs_layer_textures_);
80 base::StringAppendF(&str, "inside_vsync_ = %d; ", inside_vsync_);
81 base::StringAppendF(&str, "visible_ = %d; ", visible_);
82 base::StringAppendF(&str, "can_begin_frame_ = %d; ", can_begin_frame_);
83 base::StringAppendF(&str, "can_draw_ = %d; ", can_draw_);
84 base::StringAppendF(
85 &str, "draw_if_possible_failed_ = %d; ", draw_if_possible_failed_);
86 base::StringAppendF(&str, "has_pending_tree_ = %d; ", has_pending_tree_);
87 base::StringAppendF(&str, "texture_state_ = %d; ", texture_state_);
88 base::StringAppendF(
89 &str, "output_surface_state_ = %d; ", output_surface_state_);
90 return str;
93 bool SchedulerStateMachine::HasDrawnThisFrame() const {
94 return current_frame_number_ == last_frame_number_where_draw_was_called_;
97 bool SchedulerStateMachine::HasAttemptedTreeActivationThisFrame() const {
98 return current_frame_number_ ==
99 last_frame_number_where_tree_activation_attempted_;
102 bool SchedulerStateMachine::HasCheckedForCompletedTileUploadsThisFrame() const {
103 return current_frame_number_ ==
104 last_frame_number_where_check_for_completed_tile_uploads_called_;
107 bool SchedulerStateMachine::DrawSuspendedUntilCommit() const {
108 if (!can_draw_)
109 return true;
110 if (!visible_)
111 return true;
112 if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD)
113 return true;
114 return false;
117 bool SchedulerStateMachine::ScheduledToDraw() const {
118 if (!needs_redraw_)
119 return false;
120 if (DrawSuspendedUntilCommit())
121 return false;
122 return true;
125 bool SchedulerStateMachine::ShouldDraw() const {
126 if (needs_forced_redraw_)
127 return true;
129 if (!ScheduledToDraw())
130 return false;
131 if (!inside_vsync_)
132 return false;
133 if (HasDrawnThisFrame())
134 return false;
135 if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
136 return false;
137 return true;
140 bool SchedulerStateMachine::ShouldAttemptTreeActivation() const {
141 return has_pending_tree_ && inside_vsync_ &&
142 !HasAttemptedTreeActivationThisFrame();
145 bool SchedulerStateMachine::ShouldCheckForCompletedTileUploads() const {
146 if (!settings_.impl_side_painting)
147 return false;
148 if (HasCheckedForCompletedTileUploadsThisFrame())
149 return false;
151 return ShouldAttemptTreeActivation() || ShouldDraw() ||
152 swap_used_incomplete_tile_;
155 bool SchedulerStateMachine::ShouldAcquireLayerTexturesForMainThread() const {
156 if (!main_thread_needs_layer_textures_)
157 return false;
158 if (texture_state_ == LAYER_TEXTURE_STATE_UNLOCKED)
159 return true;
160 DCHECK_EQ(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD);
161 // Transfer the lock from impl thread to main thread immediately if the
162 // impl thread is not even scheduled to draw. Guards against deadlocking.
163 if (!ScheduledToDraw())
164 return true;
165 if (!VSyncCallbackNeeded())
166 return true;
167 return false;
170 SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
171 if (ShouldAcquireLayerTexturesForMainThread())
172 return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD;
174 switch (commit_state_) {
175 case COMMIT_STATE_IDLE:
176 if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE &&
177 needs_forced_redraw_)
178 return ACTION_DRAW_FORCED;
179 if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE &&
180 needs_forced_commit_)
181 // TODO(enne): Should probably drop the active tree on force commit.
182 return has_pending_tree_ ? ACTION_NONE : ACTION_BEGIN_FRAME;
183 if (output_surface_state_ == OUTPUT_SURFACE_LOST)
184 return ACTION_BEGIN_OUTPUT_SURFACE_RECREATION;
185 if (output_surface_state_ == OUTPUT_SURFACE_RECREATING)
186 return ACTION_NONE;
187 if (ShouldCheckForCompletedTileUploads())
188 return ACTION_CHECK_FOR_COMPLETED_TILE_UPLOADS;
189 if (ShouldAttemptTreeActivation())
190 return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
191 if (ShouldDraw()) {
192 return needs_forced_redraw_ ? ACTION_DRAW_FORCED
193 : ACTION_DRAW_IF_POSSIBLE;
195 if (needs_commit_ &&
196 ((visible_ && can_begin_frame_) || needs_forced_commit_))
197 // TODO(enne): Should probably drop the active tree on force commit.
198 return has_pending_tree_ ? ACTION_NONE : ACTION_BEGIN_FRAME;
199 return ACTION_NONE;
201 case COMMIT_STATE_FRAME_IN_PROGRESS:
202 if (ShouldCheckForCompletedTileUploads())
203 return ACTION_CHECK_FOR_COMPLETED_TILE_UPLOADS;
204 if (ShouldAttemptTreeActivation())
205 return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
206 if (ShouldDraw()) {
207 return needs_forced_redraw_ ? ACTION_DRAW_FORCED
208 : ACTION_DRAW_IF_POSSIBLE;
210 return ACTION_NONE;
212 case COMMIT_STATE_READY_TO_COMMIT:
213 return ACTION_COMMIT;
215 case COMMIT_STATE_WAITING_FOR_FIRST_DRAW: {
216 if (ShouldCheckForCompletedTileUploads())
217 return ACTION_CHECK_FOR_COMPLETED_TILE_UPLOADS;
218 if (ShouldAttemptTreeActivation())
219 return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
220 if (ShouldDraw() || output_surface_state_ == OUTPUT_SURFACE_LOST) {
221 return needs_forced_redraw_ ? ACTION_DRAW_FORCED
222 : ACTION_DRAW_IF_POSSIBLE;
224 // COMMIT_STATE_WAITING_FOR_FIRST_DRAW wants to enforce a draw. If
225 // can_draw_ is false or textures are not available, proceed to the next
226 // step (similar as in COMMIT_STATE_IDLE).
227 bool can_commit = visible_ || needs_forced_commit_;
228 if (needs_commit_ && can_commit && DrawSuspendedUntilCommit())
229 return has_pending_tree_ ? ACTION_NONE : ACTION_BEGIN_FRAME;
230 return ACTION_NONE;
233 case COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW:
234 if (ShouldCheckForCompletedTileUploads())
235 return ACTION_CHECK_FOR_COMPLETED_TILE_UPLOADS;
236 if (ShouldAttemptTreeActivation())
237 return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
238 if (needs_forced_redraw_)
239 return ACTION_DRAW_FORCED;
240 return ACTION_NONE;
242 NOTREACHED();
243 return ACTION_NONE;
246 void SchedulerStateMachine::UpdateState(Action action) {
247 switch (action) {
248 case ACTION_NONE:
249 return;
251 case ACTION_CHECK_FOR_COMPLETED_TILE_UPLOADS:
252 last_frame_number_where_check_for_completed_tile_uploads_called_ =
253 current_frame_number_;
254 return;
256 case ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED:
257 last_frame_number_where_tree_activation_attempted_ =
258 current_frame_number_;
259 return;
261 case ACTION_BEGIN_FRAME:
262 DCHECK(!has_pending_tree_);
263 DCHECK(visible_ || needs_forced_commit_);
264 commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
265 needs_commit_ = false;
266 needs_forced_commit_ = false;
267 return;
269 case ACTION_COMMIT:
270 if (expect_immediate_begin_frame_)
271 commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW;
272 else
273 commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
274 // When impl-side painting, we draw on activation instead of on commit.
275 if (!settings_.impl_side_painting)
276 needs_redraw_ = true;
277 if (draw_if_possible_failed_)
278 last_frame_number_where_draw_was_called_ = -1;
280 if (needs_forced_redraw_after_next_commit_) {
281 needs_forced_redraw_after_next_commit_ = false;
282 needs_forced_redraw_ = true;
285 texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
286 return;
288 case ACTION_DRAW_FORCED:
289 case ACTION_DRAW_IF_POSSIBLE:
290 needs_redraw_ = false;
291 needs_forced_redraw_ = false;
292 draw_if_possible_failed_ = false;
293 swap_used_incomplete_tile_ = false;
294 if (inside_vsync_)
295 last_frame_number_where_draw_was_called_ = current_frame_number_;
296 if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW) {
297 DCHECK(expect_immediate_begin_frame_);
298 commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
299 expect_immediate_begin_frame_ = false;
300 } else if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) {
301 commit_state_ = COMMIT_STATE_IDLE;
303 if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
304 texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
305 return;
307 case ACTION_BEGIN_OUTPUT_SURFACE_RECREATION:
308 DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
309 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
310 output_surface_state_ = OUTPUT_SURFACE_RECREATING;
311 return;
313 case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
314 texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD;
315 main_thread_needs_layer_textures_ = false;
316 if (commit_state_ != COMMIT_STATE_FRAME_IN_PROGRESS)
317 needs_commit_ = true;
318 return;
322 void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() {
323 DCHECK(!main_thread_needs_layer_textures_);
324 DCHECK_NE(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD);
325 main_thread_needs_layer_textures_ = true;
328 bool SchedulerStateMachine::VSyncCallbackNeeded() const {
329 // If we have a pending tree, need to keep getting notifications until
330 // the tree is ready to be swapped.
331 if (has_pending_tree_)
332 return true;
334 // If we can't draw, don't tick until we are notified that we can draw again.
335 if (!can_draw_)
336 return false;
338 if (needs_forced_redraw_)
339 return true;
341 if (visible_ && swap_used_incomplete_tile_)
342 return true;
344 return needs_redraw_ && visible_ &&
345 output_surface_state_ == OUTPUT_SURFACE_ACTIVE;
348 void SchedulerStateMachine::DidEnterVSync() { inside_vsync_ = true; }
350 void SchedulerStateMachine::DidLeaveVSync() {
351 current_frame_number_++;
352 inside_vsync_ = false;
355 void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
357 void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
359 void SchedulerStateMachine::DidSwapUseIncompleteTile() {
360 swap_used_incomplete_tile_ = true;
363 void SchedulerStateMachine::SetNeedsForcedRedraw() {
364 needs_forced_redraw_ = true;
367 void SchedulerStateMachine::DidDrawIfPossibleCompleted(bool success) {
368 draw_if_possible_failed_ = !success;
369 if (draw_if_possible_failed_) {
370 needs_redraw_ = true;
371 needs_commit_ = true;
372 consecutive_failed_draws_++;
373 if (settings_.timeout_and_draw_when_animation_checkerboards &&
374 consecutive_failed_draws_ >=
375 maximum_number_of_failed_draws_before_draw_is_forced_) {
376 consecutive_failed_draws_ = 0;
377 // We need to force a draw, but it doesn't make sense to do this until
378 // we've committed and have new textures.
379 needs_forced_redraw_after_next_commit_ = true;
381 } else {
382 consecutive_failed_draws_ = 0;
386 void SchedulerStateMachine::SetNeedsCommit() { needs_commit_ = true; }
388 void SchedulerStateMachine::SetNeedsForcedCommit() {
389 needs_forced_commit_ = true;
390 expect_immediate_begin_frame_ = true;
393 void SchedulerStateMachine::BeginFrameComplete() {
394 DCHECK(commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS ||
395 (expect_immediate_begin_frame_ && commit_state_ != COMMIT_STATE_IDLE))
396 << ToString();
397 commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
400 void SchedulerStateMachine::BeginFrameAborted() {
401 DCHECK_EQ(commit_state_, COMMIT_STATE_FRAME_IN_PROGRESS);
402 if (expect_immediate_begin_frame_) {
403 expect_immediate_begin_frame_ = false;
404 } else {
405 commit_state_ = COMMIT_STATE_IDLE;
406 SetNeedsCommit();
410 void SchedulerStateMachine::DidLoseOutputSurface() {
411 if (output_surface_state_ == OUTPUT_SURFACE_LOST ||
412 output_surface_state_ == OUTPUT_SURFACE_RECREATING)
413 return;
414 output_surface_state_ = OUTPUT_SURFACE_LOST;
417 void SchedulerStateMachine::SetHasPendingTree(bool has_pending_tree) {
418 has_pending_tree_ = has_pending_tree;
421 void SchedulerStateMachine::SetCanDraw(bool can) { can_draw_ = can; }
423 void SchedulerStateMachine::DidRecreateOutputSurface() {
424 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_RECREATING);
425 output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
426 SetNeedsCommit();
429 void SchedulerStateMachine::SetMaximumNumberOfFailedDrawsBeforeDrawIsForced(
430 int num_draws) {
431 maximum_number_of_failed_draws_before_draw_is_forced_ = num_draws;
434 } // namespace cc