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"
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),
22 swap_used_incomplete_tile_(false),
23 needs_forced_redraw_(false),
24 needs_forced_redraw_after_next_commit_(false),
26 needs_forced_commit_(false),
27 expect_immediate_begin_frame_(false),
28 main_thread_needs_layer_textures_(false),
31 can_begin_frame_(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() {
40 base::StringAppendF(&str
,
41 "settings_.impl_side_painting = %d; ",
42 settings_
.impl_side_painting
);
43 base::StringAppendF(&str
, "commit_state_ = %d; ", commit_state_
);
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_
);
51 "last_frame_number_where_tree_activation_attempted_ = %d; ",
52 last_frame_number_where_tree_activation_attempted_
);
55 "last_frame_number_where_check_for_completed_tile_uploads_called_ = %d; ",
56 last_frame_number_where_check_for_completed_tile_uploads_called_
);
58 &str
, "consecutive_failed_draws_ = %d; ", consecutive_failed_draws_
);
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_
);
65 &str
, "swap_used_incomplete_tile_ = %d; ", swap_used_incomplete_tile_
);
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_
);
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_
);
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_
);
89 &str
, "output_surface_state_ = %d; ", output_surface_state_
);
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 {
112 if (texture_state_
== LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD
)
117 bool SchedulerStateMachine::ScheduledToDraw() const {
120 if (DrawSuspendedUntilCommit())
125 bool SchedulerStateMachine::ShouldDraw() const {
126 if (needs_forced_redraw_
)
129 if (!ScheduledToDraw())
133 if (HasDrawnThisFrame())
135 if (output_surface_state_
!= OUTPUT_SURFACE_ACTIVE
)
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
)
148 if (HasCheckedForCompletedTileUploadsThisFrame())
151 return ShouldAttemptTreeActivation() || ShouldDraw() ||
152 swap_used_incomplete_tile_
;
155 bool SchedulerStateMachine::ShouldAcquireLayerTexturesForMainThread() const {
156 if (!main_thread_needs_layer_textures_
)
158 if (texture_state_
== LAYER_TEXTURE_STATE_UNLOCKED
)
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())
165 if (!VSyncCallbackNeeded())
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
)
187 if (ShouldCheckForCompletedTileUploads())
188 return ACTION_CHECK_FOR_COMPLETED_TILE_UPLOADS
;
189 if (ShouldAttemptTreeActivation())
190 return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED
;
192 return needs_forced_redraw_
? ACTION_DRAW_FORCED
193 : ACTION_DRAW_IF_POSSIBLE
;
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
;
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
;
207 return needs_forced_redraw_
? ACTION_DRAW_FORCED
208 : ACTION_DRAW_IF_POSSIBLE
;
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
;
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
;
246 void SchedulerStateMachine::UpdateState(Action action
) {
251 case ACTION_CHECK_FOR_COMPLETED_TILE_UPLOADS
:
252 last_frame_number_where_check_for_completed_tile_uploads_called_
=
253 current_frame_number_
;
256 case ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED
:
257 last_frame_number_where_tree_activation_attempted_
=
258 current_frame_number_
;
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;
270 if (expect_immediate_begin_frame_
)
271 commit_state_
= COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW
;
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
;
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;
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
;
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
;
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;
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_
)
334 // If we can't draw, don't tick until we are notified that we can draw again.
338 if (needs_forced_redraw_
)
341 if (visible_
&& swap_used_incomplete_tile_
)
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;
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
))
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;
405 commit_state_
= COMMIT_STATE_IDLE
;
410 void SchedulerStateMachine::DidLoseOutputSurface() {
411 if (output_surface_state_
== OUTPUT_SURFACE_LOST
||
412 output_surface_state_
== OUTPUT_SURFACE_RECREATING
)
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
;
429 void SchedulerStateMachine::SetMaximumNumberOfFailedDrawsBeforeDrawIsForced(
431 maximum_number_of_failed_draws_before_draw_is_forced_
= num_draws
;