OLD | NEW |
1 // Copyright 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/scheduler/scheduler_state_machine.h" | 5 #include "cc/scheduler/scheduler_state_machine.h" |
6 | 6 |
7 #include "base/format_macros.h" | 7 #include "base/format_macros.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
10 #include "base/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.h" |
11 #include "base/trace_event/trace_event_argument.h" | 11 #include "base/trace_event/trace_event_argument.h" |
12 #include "base/values.h" | 12 #include "base/values.h" |
13 | 13 |
14 namespace cc { | 14 namespace cc { |
15 | 15 |
16 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) | 16 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
17 : settings_(settings), | 17 : settings_(settings), |
18 output_surface_state_(OUTPUT_SURFACE_LOST), | 18 output_surface_state_(OUTPUT_SURFACE_NONE), |
19 begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE), | 19 begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE), |
20 begin_main_frame_state_(BEGIN_MAIN_FRAME_STATE_IDLE), | 20 begin_main_frame_state_(BEGIN_MAIN_FRAME_STATE_IDLE), |
21 forced_redraw_state_(FORCED_REDRAW_STATE_IDLE), | 21 forced_redraw_state_(FORCED_REDRAW_STATE_IDLE), |
22 commit_count_(0), | 22 commit_count_(0), |
23 current_frame_number_(0), | 23 current_frame_number_(0), |
24 last_frame_number_animate_performed_(-1), | 24 last_frame_number_animate_performed_(-1), |
25 last_frame_number_swap_performed_(-1), | 25 last_frame_number_swap_performed_(-1), |
26 last_frame_number_swap_requested_(-1), | 26 last_frame_number_swap_requested_(-1), |
27 last_frame_number_begin_main_frame_sent_(-1), | 27 last_frame_number_begin_main_frame_sent_(-1), |
28 last_frame_number_invalidate_output_surface_performed_(-1), | 28 last_frame_number_invalidate_output_surface_performed_(-1), |
29 animate_funnel_(false), | 29 animate_funnel_(false), |
30 request_swap_funnel_(false), | 30 request_swap_funnel_(false), |
31 send_begin_main_frame_funnel_(true), | 31 send_begin_main_frame_funnel_(true), |
32 invalidate_output_surface_funnel_(false), | 32 invalidate_output_surface_funnel_(false), |
33 prepare_tiles_funnel_(0), | 33 prepare_tiles_funnel_(0), |
34 consecutive_checkerboard_animations_(0), | 34 consecutive_checkerboard_animations_(0), |
35 max_pending_swaps_(1), | 35 max_pending_swaps_(1), |
36 pending_swaps_(0), | 36 pending_swaps_(0), |
37 swaps_with_current_output_surface_(0), | 37 swaps_with_current_output_surface_(0), |
38 needs_redraw_(false), | 38 needs_redraw_(false), |
39 needs_animate_(false), | 39 needs_animate_(false), |
40 needs_prepare_tiles_(false), | 40 needs_prepare_tiles_(false), |
41 needs_begin_main_frame_(false), | 41 needs_begin_main_frame_(false), |
42 visible_(false), | 42 visible_(false), |
43 can_start_(false), | |
44 can_draw_(false), | 43 can_draw_(false), |
45 has_pending_tree_(false), | 44 has_pending_tree_(false), |
46 pending_tree_is_ready_for_activation_(false), | 45 pending_tree_is_ready_for_activation_(false), |
47 active_tree_needs_first_draw_(false), | 46 active_tree_needs_first_draw_(false), |
48 did_create_and_initialize_first_output_surface_(false), | 47 did_create_and_initialize_first_output_surface_(false), |
49 impl_latency_takes_priority_(false), | 48 impl_latency_takes_priority_(false), |
50 main_thread_missed_last_deadline_(false), | 49 main_thread_missed_last_deadline_(false), |
51 skip_next_begin_main_frame_to_reduce_latency_(false), | 50 skip_next_begin_main_frame_to_reduce_latency_(false), |
52 children_need_begin_frames_(false), | 51 children_need_begin_frames_(false), |
53 defer_commits_(false), | 52 defer_commits_(false), |
54 video_needs_begin_frames_(false), | 53 video_needs_begin_frames_(false), |
55 last_commit_had_no_updates_(false), | 54 last_commit_had_no_updates_(false), |
56 wait_for_ready_to_draw_(false), | 55 wait_for_ready_to_draw_(false), |
57 did_request_swap_in_last_frame_(false), | 56 did_request_swap_in_last_frame_(false), |
58 did_perform_swap_in_last_draw_(false) {} | 57 did_perform_swap_in_last_draw_(false) {} |
59 | 58 |
60 const char* SchedulerStateMachine::OutputSurfaceStateToString( | 59 const char* SchedulerStateMachine::OutputSurfaceStateToString( |
61 OutputSurfaceState state) { | 60 OutputSurfaceState state) { |
62 switch (state) { | 61 switch (state) { |
| 62 case OUTPUT_SURFACE_NONE: |
| 63 return "OUTPUT_SURFACE_NONE"; |
63 case OUTPUT_SURFACE_ACTIVE: | 64 case OUTPUT_SURFACE_ACTIVE: |
64 return "OUTPUT_SURFACE_ACTIVE"; | 65 return "OUTPUT_SURFACE_ACTIVE"; |
65 case OUTPUT_SURFACE_LOST: | |
66 return "OUTPUT_SURFACE_LOST"; | |
67 case OUTPUT_SURFACE_CREATING: | 66 case OUTPUT_SURFACE_CREATING: |
68 return "OUTPUT_SURFACE_CREATING"; | 67 return "OUTPUT_SURFACE_CREATING"; |
69 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT: | 68 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT: |
70 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT"; | 69 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT"; |
71 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION: | 70 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION: |
72 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION"; | 71 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION"; |
73 } | 72 } |
74 NOTREACHED(); | 73 NOTREACHED(); |
75 return "???"; | 74 return "???"; |
76 } | 75 } |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 consecutive_checkerboard_animations_); | 217 consecutive_checkerboard_animations_); |
219 state->SetInteger("max_pending_swaps_", max_pending_swaps_); | 218 state->SetInteger("max_pending_swaps_", max_pending_swaps_); |
220 state->SetInteger("pending_swaps_", pending_swaps_); | 219 state->SetInteger("pending_swaps_", pending_swaps_); |
221 state->SetInteger("swaps_with_current_output_surface", | 220 state->SetInteger("swaps_with_current_output_surface", |
222 swaps_with_current_output_surface_); | 221 swaps_with_current_output_surface_); |
223 state->SetBoolean("needs_redraw", needs_redraw_); | 222 state->SetBoolean("needs_redraw", needs_redraw_); |
224 state->SetBoolean("needs_animate_", needs_animate_); | 223 state->SetBoolean("needs_animate_", needs_animate_); |
225 state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_); | 224 state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_); |
226 state->SetBoolean("needs_begin_main_frame", needs_begin_main_frame_); | 225 state->SetBoolean("needs_begin_main_frame", needs_begin_main_frame_); |
227 state->SetBoolean("visible", visible_); | 226 state->SetBoolean("visible", visible_); |
228 state->SetBoolean("can_start", can_start_); | |
229 state->SetBoolean("can_draw", can_draw_); | 227 state->SetBoolean("can_draw", can_draw_); |
230 state->SetBoolean("has_pending_tree", has_pending_tree_); | 228 state->SetBoolean("has_pending_tree", has_pending_tree_); |
231 state->SetBoolean("pending_tree_is_ready_for_activation", | 229 state->SetBoolean("pending_tree_is_ready_for_activation", |
232 pending_tree_is_ready_for_activation_); | 230 pending_tree_is_ready_for_activation_); |
233 state->SetBoolean("active_tree_needs_first_draw", | 231 state->SetBoolean("active_tree_needs_first_draw", |
234 active_tree_needs_first_draw_); | 232 active_tree_needs_first_draw_); |
235 state->SetBoolean("wait_for_ready_to_draw", wait_for_ready_to_draw_); | 233 state->SetBoolean("wait_for_ready_to_draw", wait_for_ready_to_draw_); |
236 state->SetBoolean("did_create_and_initialize_first_output_surface", | 234 state->SetBoolean("did_create_and_initialize_first_output_surface", |
237 did_create_and_initialize_first_output_surface_); | 235 did_create_and_initialize_first_output_surface_); |
238 state->SetBoolean("impl_latency_takes_priority", | 236 state->SetBoolean("impl_latency_takes_priority", |
(...skipping 11 matching lines...) Expand all Loading... |
250 state->SetBoolean("did_perform_swap_in_last_draw", | 248 state->SetBoolean("did_perform_swap_in_last_draw", |
251 did_perform_swap_in_last_draw_); | 249 did_perform_swap_in_last_draw_); |
252 state->EndDictionary(); | 250 state->EndDictionary(); |
253 } | 251 } |
254 | 252 |
255 bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { | 253 bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { |
256 // Normally when |visible_| is false, pending activations will be forced and | 254 // Normally when |visible_| is false, pending activations will be forced and |
257 // draws will be aborted. However, when the embedder is Android WebView, | 255 // draws will be aborted. However, when the embedder is Android WebView, |
258 // software draws could be scheduled by the Android OS at any time and draws | 256 // software draws could be scheduled by the Android OS at any time and draws |
259 // should not be aborted in this case. | 257 // should not be aborted in this case. |
260 bool is_output_surface_lost = (output_surface_state_ == OUTPUT_SURFACE_LOST); | 258 bool is_output_surface_lost = (output_surface_state_ == OUTPUT_SURFACE_NONE); |
261 if (settings_.using_synchronous_renderer_compositor) | 259 if (settings_.using_synchronous_renderer_compositor) |
262 return is_output_surface_lost || !can_draw_; | 260 return is_output_surface_lost || !can_draw_; |
263 | 261 |
264 // These are all the cases where we normally cannot or do not want to draw | 262 // These are all the cases where we normally cannot or do not want to draw |
265 // but, if needs_redraw_ is true and we do not draw to make forward progress, | 263 // but, if needs_redraw_ is true and we do not draw to make forward progress, |
266 // we might deadlock with the main thread. | 264 // we might deadlock with the main thread. |
267 // This should be a superset of PendingActivationsShouldBeForced() since | 265 // This should be a superset of PendingActivationsShouldBeForced() since |
268 // activation of the pending tree is blocked by drawing of the active tree and | 266 // activation of the pending tree is blocked by drawing of the active tree and |
269 // the main thread might be blocked on activation of the most recent commit. | 267 // the main thread might be blocked on activation of the most recent commit. |
270 return is_output_surface_lost || !can_draw_ || !visible_; | 268 return is_output_surface_lost || !can_draw_ || !visible_; |
271 } | 269 } |
272 | 270 |
273 bool SchedulerStateMachine::PendingActivationsShouldBeForced() const { | 271 bool SchedulerStateMachine::PendingActivationsShouldBeForced() const { |
274 // There is no output surface to trigger our activations. | 272 // There is no output surface to trigger our activations. |
275 // If we do not force activations to make forward progress, we might deadlock | 273 // If we do not force activations to make forward progress, we might deadlock |
276 // with the main thread. | 274 // with the main thread. |
277 if (output_surface_state_ == OUTPUT_SURFACE_LOST) | 275 if (output_surface_state_ == OUTPUT_SURFACE_NONE) |
278 return true; | 276 return true; |
279 | 277 |
280 // If we're not visible, we should force activation. | 278 // If we're not visible, we should force activation. |
281 // Since we set RequiresHighResToDraw when becoming visible, we ensure that we | 279 // Since we set RequiresHighResToDraw when becoming visible, we ensure that we |
282 // don't checkerboard until all visible resources are done. Furthermore, if we | 280 // don't checkerboard until all visible resources are done. Furthermore, if we |
283 // do keep the pending tree around, when becoming visible we might activate | 281 // do keep the pending tree around, when becoming visible we might activate |
284 // prematurely causing RequiresHighResToDraw flag to be reset. In all cases, | 282 // prematurely causing RequiresHighResToDraw flag to be reset. In all cases, |
285 // we can simply activate on becoming invisible since we don't need to draw | 283 // we can simply activate on becoming invisible since we don't need to draw |
286 // the active tree when we're in this state. | 284 // the active tree when we're in this state. |
287 if (!visible_) | 285 if (!visible_) |
288 return true; | 286 return true; |
289 | 287 |
290 return false; | 288 return false; |
291 } | 289 } |
292 | 290 |
293 bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const { | 291 bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const { |
294 if (!visible_) | 292 if (!visible_) |
295 return false; | 293 return false; |
296 | 294 |
297 // Don't try to initialize too early. | |
298 if (!can_start_) | |
299 return false; | |
300 | |
301 // We only want to start output surface initialization after the | 295 // We only want to start output surface initialization after the |
302 // previous commit is complete. | 296 // previous commit is complete. |
303 if (begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE) | 297 if (begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE) |
304 return false; | 298 return false; |
305 | 299 |
306 // Make sure the BeginImplFrame from any previous OutputSurfaces | 300 // Make sure the BeginImplFrame from any previous OutputSurfaces |
307 // are complete before creating the new OutputSurface. | 301 // are complete before creating the new OutputSurface. |
308 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE) | 302 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE) |
309 return false; | 303 return false; |
310 | 304 |
311 // We want to clear the pipeline of any pending draws and activations | 305 // We want to clear the pipeline of any pending draws and activations |
312 // before starting output surface initialization. This allows us to avoid | 306 // before starting output surface initialization. This allows us to avoid |
313 // weird corner cases where we abort draws or force activation while we | 307 // weird corner cases where we abort draws or force activation while we |
314 // are initializing the output surface. | 308 // are initializing the output surface. |
315 if (active_tree_needs_first_draw_ || has_pending_tree_) | 309 if (active_tree_needs_first_draw_ || has_pending_tree_) |
316 return false; | 310 return false; |
317 | 311 |
318 // We need to create the output surface if we don't have one and we haven't | 312 // We need to create the output surface if we don't have one and we haven't |
319 // started creating one yet. | 313 // started creating one yet. |
320 return output_surface_state_ == OUTPUT_SURFACE_LOST; | 314 return output_surface_state_ == OUTPUT_SURFACE_NONE; |
321 } | 315 } |
322 | 316 |
323 bool SchedulerStateMachine::ShouldDraw() const { | 317 bool SchedulerStateMachine::ShouldDraw() const { |
324 // If we need to abort draws, we should do so ASAP since the draw could | 318 // If we need to abort draws, we should do so ASAP since the draw could |
325 // be blocking other important actions (like output surface initialization), | 319 // be blocking other important actions (like output surface initialization), |
326 // from occurring. If we are waiting for the first draw, then perform the | 320 // from occurring. If we are waiting for the first draw, then perform the |
327 // aborted draw to keep things moving. If we are not waiting for the first | 321 // aborted draw to keep things moving. If we are not waiting for the first |
328 // draw however, we don't want to abort for no reason. | 322 // draw however, we don't want to abort for no reason. |
329 if (PendingDrawsShouldBeAborted()) | 323 if (PendingDrawsShouldBeAborted()) |
330 return active_tree_needs_first_draw_; | 324 return active_tree_needs_first_draw_; |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
669 did_request_swap_in_last_frame_ = true; | 663 did_request_swap_in_last_frame_ = true; |
670 last_frame_number_swap_requested_ = current_frame_number_; | 664 last_frame_number_swap_requested_ = current_frame_number_; |
671 } | 665 } |
672 } | 666 } |
673 | 667 |
674 void SchedulerStateMachine::WillPrepareTiles() { | 668 void SchedulerStateMachine::WillPrepareTiles() { |
675 needs_prepare_tiles_ = false; | 669 needs_prepare_tiles_ = false; |
676 } | 670 } |
677 | 671 |
678 void SchedulerStateMachine::WillBeginOutputSurfaceCreation() { | 672 void SchedulerStateMachine::WillBeginOutputSurfaceCreation() { |
679 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST); | 673 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_NONE); |
680 output_surface_state_ = OUTPUT_SURFACE_CREATING; | 674 output_surface_state_ = OUTPUT_SURFACE_CREATING; |
681 | 675 |
682 // The following DCHECKs make sure we are in the proper quiescent state. | 676 // The following DCHECKs make sure we are in the proper quiescent state. |
683 // The pipeline should be flushed entirely before we start output | 677 // The pipeline should be flushed entirely before we start output |
684 // surface creation to avoid complicated corner cases. | 678 // surface creation to avoid complicated corner cases. |
685 DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_IDLE); | 679 DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_IDLE); |
686 DCHECK(!has_pending_tree_); | 680 DCHECK(!has_pending_tree_); |
687 DCHECK(!active_tree_needs_first_draw_); | 681 DCHECK(!active_tree_needs_first_draw_); |
688 } | 682 } |
689 | 683 |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1056 } | 1050 } |
1057 } | 1051 } |
1058 | 1052 |
1059 void SchedulerStateMachine::DidPrepareTiles() { | 1053 void SchedulerStateMachine::DidPrepareTiles() { |
1060 needs_prepare_tiles_ = false; | 1054 needs_prepare_tiles_ = false; |
1061 // "Fill" the PrepareTiles funnel. | 1055 // "Fill" the PrepareTiles funnel. |
1062 prepare_tiles_funnel_++; | 1056 prepare_tiles_funnel_++; |
1063 } | 1057 } |
1064 | 1058 |
1065 void SchedulerStateMachine::DidLoseOutputSurface() { | 1059 void SchedulerStateMachine::DidLoseOutputSurface() { |
1066 if (output_surface_state_ == OUTPUT_SURFACE_LOST || | 1060 if (output_surface_state_ == OUTPUT_SURFACE_NONE || |
1067 output_surface_state_ == OUTPUT_SURFACE_CREATING) | 1061 output_surface_state_ == OUTPUT_SURFACE_CREATING) |
1068 return; | 1062 return; |
1069 output_surface_state_ = OUTPUT_SURFACE_LOST; | 1063 output_surface_state_ = OUTPUT_SURFACE_NONE; |
1070 needs_redraw_ = false; | 1064 needs_redraw_ = false; |
1071 wait_for_ready_to_draw_ = false; | 1065 wait_for_ready_to_draw_ = false; |
1072 } | 1066 } |
1073 | 1067 |
1074 void SchedulerStateMachine::NotifyReadyToActivate() { | 1068 void SchedulerStateMachine::NotifyReadyToActivate() { |
1075 if (has_pending_tree_) | 1069 if (has_pending_tree_) |
1076 pending_tree_is_ready_for_activation_ = true; | 1070 pending_tree_is_ready_for_activation_ = true; |
1077 } | 1071 } |
1078 | 1072 |
1079 void SchedulerStateMachine::NotifyReadyToDraw() { | 1073 void SchedulerStateMachine::NotifyReadyToDraw() { |
(...skipping 15 matching lines...) Expand all Loading... |
1095 main_thread_missed_last_deadline_ = false; | 1089 main_thread_missed_last_deadline_ = false; |
1096 } | 1090 } |
1097 | 1091 |
1098 void SchedulerStateMachine::NotifyBeginMainFrameStarted() { | 1092 void SchedulerStateMachine::NotifyBeginMainFrameStarted() { |
1099 DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_SENT); | 1093 DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_SENT); |
1100 begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_STARTED; | 1094 begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_STARTED; |
1101 } | 1095 } |
1102 | 1096 |
1103 bool SchedulerStateMachine::HasInitializedOutputSurface() const { | 1097 bool SchedulerStateMachine::HasInitializedOutputSurface() const { |
1104 switch (output_surface_state_) { | 1098 switch (output_surface_state_) { |
1105 case OUTPUT_SURFACE_LOST: | 1099 case OUTPUT_SURFACE_NONE: |
1106 case OUTPUT_SURFACE_CREATING: | 1100 case OUTPUT_SURFACE_CREATING: |
1107 return false; | 1101 return false; |
1108 | 1102 |
1109 case OUTPUT_SURFACE_ACTIVE: | 1103 case OUTPUT_SURFACE_ACTIVE: |
1110 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT: | 1104 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT: |
1111 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION: | 1105 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION: |
1112 return true; | 1106 return true; |
1113 } | 1107 } |
1114 NOTREACHED(); | 1108 NOTREACHED(); |
1115 return false; | 1109 return false; |
1116 } | 1110 } |
1117 | 1111 |
1118 } // namespace cc | 1112 } // namespace cc |
OLD | NEW |