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 #include "ui/gfx/frame_time.h" | 13 #include "ui/gfx/frame_time.h" |
14 | 14 |
15 namespace cc { | 15 namespace cc { |
16 | 16 |
17 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) | 17 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
18 : settings_(settings), | 18 : settings_(settings), |
19 output_surface_state_(OUTPUT_SURFACE_LOST), | 19 output_surface_state_(OUTPUT_SURFACE_LOST), |
20 begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE), | 20 begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE), |
21 commit_state_(COMMIT_STATE_IDLE), | 21 commit_state_(COMMIT_STATE_IDLE), |
22 forced_redraw_state_(FORCED_REDRAW_STATE_IDLE), | 22 forced_redraw_state_(FORCED_REDRAW_STATE_IDLE), |
23 commit_count_(0), | 23 commit_count_(0), |
24 current_frame_number_(0), | 24 current_frame_number_(0), |
25 last_frame_number_animate_performed_(-1), | 25 last_frame_number_animate_performed_(-1), |
26 last_frame_number_swap_performed_(-1), | 26 last_frame_number_swap_performed_(-1), |
27 last_frame_number_swap_requested_(-1), | 27 last_frame_number_swap_requested_(-1), |
28 last_frame_number_begin_main_frame_sent_(-1), | 28 last_frame_number_begin_main_frame_sent_(-1), |
| 29 last_frame_number_invalidate_output_surface_performed_(-1), |
29 animate_funnel_(false), | 30 animate_funnel_(false), |
30 perform_swap_funnel_(false), | 31 perform_swap_funnel_(false), |
31 request_swap_funnel_(false), | 32 request_swap_funnel_(false), |
32 send_begin_main_frame_funnel_(false), | 33 send_begin_main_frame_funnel_(false), |
| 34 invalidate_output_surface_funnel_(false), |
33 prepare_tiles_funnel_(0), | 35 prepare_tiles_funnel_(0), |
34 consecutive_checkerboard_animations_(0), | 36 consecutive_checkerboard_animations_(0), |
35 max_pending_swaps_(1), | 37 max_pending_swaps_(1), |
36 pending_swaps_(0), | 38 pending_swaps_(0), |
37 needs_redraw_(false), | 39 needs_redraw_(false), |
38 needs_animate_(false), | 40 needs_animate_(false), |
39 needs_prepare_tiles_(false), | 41 needs_prepare_tiles_(false), |
40 needs_commit_(false), | 42 needs_commit_(false), |
41 inside_poll_for_anticipated_draw_triggers_(false), | |
42 visible_(false), | 43 visible_(false), |
43 can_start_(false), | 44 can_start_(false), |
44 can_draw_(false), | 45 can_draw_(false), |
45 has_pending_tree_(false), | 46 has_pending_tree_(false), |
46 pending_tree_is_ready_for_activation_(false), | 47 pending_tree_is_ready_for_activation_(false), |
47 active_tree_needs_first_draw_(false), | 48 active_tree_needs_first_draw_(false), |
48 did_create_and_initialize_first_output_surface_(false), | 49 did_create_and_initialize_first_output_surface_(false), |
49 impl_latency_takes_priority_(false), | 50 impl_latency_takes_priority_(false), |
50 skip_next_begin_main_frame_to_reduce_latency_(false), | 51 skip_next_begin_main_frame_to_reduce_latency_(false), |
51 skip_begin_main_frame_to_reduce_latency_(false), | 52 skip_begin_main_frame_to_reduce_latency_(false), |
(...skipping 29 matching lines...) Expand all Loading... |
81 return "BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING"; | 82 return "BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING"; |
82 case BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME: | 83 case BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME: |
83 return "BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME"; | 84 return "BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME"; |
84 case BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE: | 85 case BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE: |
85 return "BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE"; | 86 return "BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE"; |
86 } | 87 } |
87 NOTREACHED(); | 88 NOTREACHED(); |
88 return "???"; | 89 return "???"; |
89 } | 90 } |
90 | 91 |
| 92 const char* SchedulerStateMachine::BeginImplFrameDeadlineModeToString( |
| 93 BeginImplFrameDeadlineMode mode) { |
| 94 switch (mode) { |
| 95 case BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE: |
| 96 return "BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE"; |
| 97 case BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE: |
| 98 return "BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE"; |
| 99 case BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR: |
| 100 return "BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR"; |
| 101 case BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE: |
| 102 return "BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE"; |
| 103 } |
| 104 NOTREACHED(); |
| 105 return "???"; |
| 106 } |
| 107 |
91 const char* SchedulerStateMachine::CommitStateToString(CommitState state) { | 108 const char* SchedulerStateMachine::CommitStateToString(CommitState state) { |
92 switch (state) { | 109 switch (state) { |
93 case COMMIT_STATE_IDLE: | 110 case COMMIT_STATE_IDLE: |
94 return "COMMIT_STATE_IDLE"; | 111 return "COMMIT_STATE_IDLE"; |
95 case COMMIT_STATE_BEGIN_MAIN_FRAME_SENT: | 112 case COMMIT_STATE_BEGIN_MAIN_FRAME_SENT: |
96 return "COMMIT_STATE_BEGIN_MAIN_FRAME_SENT"; | 113 return "COMMIT_STATE_BEGIN_MAIN_FRAME_SENT"; |
97 case COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED: | 114 case COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED: |
98 return "COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED"; | 115 return "COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED"; |
99 case COMMIT_STATE_READY_TO_COMMIT: | 116 case COMMIT_STATE_READY_TO_COMMIT: |
100 return "COMMIT_STATE_READY_TO_COMMIT"; | 117 return "COMMIT_STATE_READY_TO_COMMIT"; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: | 155 case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: |
139 return "ACTION_DRAW_AND_SWAP_IF_POSSIBLE"; | 156 return "ACTION_DRAW_AND_SWAP_IF_POSSIBLE"; |
140 case ACTION_DRAW_AND_SWAP_FORCED: | 157 case ACTION_DRAW_AND_SWAP_FORCED: |
141 return "ACTION_DRAW_AND_SWAP_FORCED"; | 158 return "ACTION_DRAW_AND_SWAP_FORCED"; |
142 case ACTION_DRAW_AND_SWAP_ABORT: | 159 case ACTION_DRAW_AND_SWAP_ABORT: |
143 return "ACTION_DRAW_AND_SWAP_ABORT"; | 160 return "ACTION_DRAW_AND_SWAP_ABORT"; |
144 case ACTION_BEGIN_OUTPUT_SURFACE_CREATION: | 161 case ACTION_BEGIN_OUTPUT_SURFACE_CREATION: |
145 return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION"; | 162 return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION"; |
146 case ACTION_PREPARE_TILES: | 163 case ACTION_PREPARE_TILES: |
147 return "ACTION_PREPARE_TILES"; | 164 return "ACTION_PREPARE_TILES"; |
| 165 case ACTION_INVALIDATE_OUTPUT_SURFACE: |
| 166 return "ACTION_INVALIDATE_OUTPUT_SURFACE"; |
148 } | 167 } |
149 NOTREACHED(); | 168 NOTREACHED(); |
150 return "???"; | 169 return "???"; |
151 } | 170 } |
152 | 171 |
153 scoped_refptr<base::trace_event::ConvertableToTraceFormat> | 172 scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
154 SchedulerStateMachine::AsValue() const { | 173 SchedulerStateMachine::AsValue() const { |
155 scoped_refptr<base::trace_event::TracedValue> state = | 174 scoped_refptr<base::trace_event::TracedValue> state = |
156 new base::trace_event::TracedValue(); | 175 new base::trace_event::TracedValue(); |
157 AsValueInto(state.get()); | 176 AsValueInto(state.get()); |
(...skipping 23 matching lines...) Expand all Loading... |
181 state->SetInteger("last_frame_number_swap_requested", | 200 state->SetInteger("last_frame_number_swap_requested", |
182 last_frame_number_swap_requested_); | 201 last_frame_number_swap_requested_); |
183 state->SetInteger("last_frame_number_begin_main_frame_sent", | 202 state->SetInteger("last_frame_number_begin_main_frame_sent", |
184 last_frame_number_begin_main_frame_sent_); | 203 last_frame_number_begin_main_frame_sent_); |
185 state->SetBoolean("funnel: animate_funnel", animate_funnel_); | 204 state->SetBoolean("funnel: animate_funnel", animate_funnel_); |
186 state->SetBoolean("funnel: perform_swap_funnel", perform_swap_funnel_); | 205 state->SetBoolean("funnel: perform_swap_funnel", perform_swap_funnel_); |
187 state->SetBoolean("funnel: request_swap_funnel", request_swap_funnel_); | 206 state->SetBoolean("funnel: request_swap_funnel", request_swap_funnel_); |
188 state->SetBoolean("funnel: send_begin_main_frame_funnel", | 207 state->SetBoolean("funnel: send_begin_main_frame_funnel", |
189 send_begin_main_frame_funnel_); | 208 send_begin_main_frame_funnel_); |
190 state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_); | 209 state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_); |
| 210 state->SetBoolean("funnel: invalidate_output_surface_funnel", |
| 211 invalidate_output_surface_funnel_); |
191 state->SetInteger("consecutive_checkerboard_animations", | 212 state->SetInteger("consecutive_checkerboard_animations", |
192 consecutive_checkerboard_animations_); | 213 consecutive_checkerboard_animations_); |
193 state->SetInteger("max_pending_swaps_", max_pending_swaps_); | 214 state->SetInteger("max_pending_swaps_", max_pending_swaps_); |
194 state->SetInteger("pending_swaps_", pending_swaps_); | 215 state->SetInteger("pending_swaps_", pending_swaps_); |
195 state->SetBoolean("needs_redraw", needs_redraw_); | 216 state->SetBoolean("needs_redraw", needs_redraw_); |
196 state->SetBoolean("needs_animate_", needs_animate_); | 217 state->SetBoolean("needs_animate_", needs_animate_); |
197 state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_); | 218 state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_); |
198 state->SetBoolean("needs_commit", needs_commit_); | 219 state->SetBoolean("needs_commit", needs_commit_); |
199 state->SetBoolean("visible", visible_); | 220 state->SetBoolean("visible", visible_); |
200 state->SetBoolean("can_start", can_start_); | 221 state->SetBoolean("can_start", can_start_); |
(...skipping 12 matching lines...) Expand all Loading... |
213 state->SetBoolean("skip_begin_main_frame_to_reduce_latency", | 234 state->SetBoolean("skip_begin_main_frame_to_reduce_latency", |
214 skip_begin_main_frame_to_reduce_latency_); | 235 skip_begin_main_frame_to_reduce_latency_); |
215 state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency", | 236 state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency", |
216 skip_next_begin_main_frame_to_reduce_latency_); | 237 skip_next_begin_main_frame_to_reduce_latency_); |
217 state->SetBoolean("continuous_painting", continuous_painting_); | 238 state->SetBoolean("continuous_painting", continuous_painting_); |
218 state->SetBoolean("children_need_begin_frames", children_need_begin_frames_); | 239 state->SetBoolean("children_need_begin_frames", children_need_begin_frames_); |
219 state->SetBoolean("defer_commits", defer_commits_); | 240 state->SetBoolean("defer_commits", defer_commits_); |
220 state->EndDictionary(); | 241 state->EndDictionary(); |
221 } | 242 } |
222 | 243 |
223 void SchedulerStateMachine::AdvanceCurrentFrameNumber() { | |
224 current_frame_number_++; | |
225 | |
226 animate_funnel_ = false; | |
227 perform_swap_funnel_ = false; | |
228 request_swap_funnel_ = false; | |
229 send_begin_main_frame_funnel_ = false; | |
230 | |
231 // "Drain" the PrepareTiles funnel. | |
232 if (prepare_tiles_funnel_ > 0) | |
233 prepare_tiles_funnel_--; | |
234 | |
235 skip_begin_main_frame_to_reduce_latency_ = | |
236 skip_next_begin_main_frame_to_reduce_latency_; | |
237 skip_next_begin_main_frame_to_reduce_latency_ = false; | |
238 } | |
239 | |
240 bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { | 244 bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { |
241 // These are all the cases where we normally cannot or do not want to draw | 245 // These are all the cases where we normally cannot or do not want to draw |
242 // but, if needs_redraw_ is true and we do not draw to make forward progress, | 246 // but, if needs_redraw_ is true and we do not draw to make forward progress, |
243 // we might deadlock with the main thread. | 247 // we might deadlock with the main thread. |
244 // This should be a superset of PendingActivationsShouldBeForced() since | 248 // This should be a superset of PendingActivationsShouldBeForced() since |
245 // activation of the pending tree is blocked by drawing of the active tree and | 249 // activation of the pending tree is blocked by drawing of the active tree and |
246 // the main thread might be blocked on activation of the most recent commit. | 250 // the main thread might be blocked on activation of the most recent commit. |
247 if (PendingActivationsShouldBeForced()) | 251 if (PendingActivationsShouldBeForced()) |
248 return true; | 252 return true; |
249 | 253 |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 } | 458 } |
455 | 459 |
456 bool SchedulerStateMachine::ShouldPrepareTiles() const { | 460 bool SchedulerStateMachine::ShouldPrepareTiles() const { |
457 // PrepareTiles only really needs to be called immediately after commit | 461 // PrepareTiles only really needs to be called immediately after commit |
458 // and then periodically after that. Use a funnel to make sure we average | 462 // and then periodically after that. Use a funnel to make sure we average |
459 // one PrepareTiles per BeginImplFrame in the long run. | 463 // one PrepareTiles per BeginImplFrame in the long run. |
460 if (prepare_tiles_funnel_ > 0) | 464 if (prepare_tiles_funnel_ > 0) |
461 return false; | 465 return false; |
462 | 466 |
463 // Limiting to once per-frame is not enough, since we only want to | 467 // Limiting to once per-frame is not enough, since we only want to |
464 // prepare tiles _after_ draws. Polling for draw triggers and | 468 // prepare tiles _after_ draws. |
465 // begin-frame are mutually exclusive, so we limit to these two cases. | 469 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) |
466 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE && | |
467 !inside_poll_for_anticipated_draw_triggers_) | |
468 return false; | 470 return false; |
| 471 |
469 return needs_prepare_tiles_; | 472 return needs_prepare_tiles_; |
470 } | 473 } |
471 | 474 |
| 475 bool SchedulerStateMachine::ShouldInvalidateOutputSurface() const { |
| 476 // Do not invalidate too many times in a frame. |
| 477 if (invalidate_output_surface_funnel_) |
| 478 return false; |
| 479 |
| 480 // Only the synchronous compositor requires invalidations. |
| 481 if (!settings_.using_synchronous_renderer_compositor) |
| 482 return false; |
| 483 |
| 484 // Invalidations are only performed inside a BeginFrame or inside deadline. |
| 485 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING && |
| 486 begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) |
| 487 return false; |
| 488 |
| 489 return needs_redraw_ || needs_prepare_tiles_; |
| 490 } |
| 491 |
472 SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { | 492 SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
473 if (ShouldActivatePendingTree()) | 493 if (ShouldActivatePendingTree()) |
474 return ACTION_ACTIVATE_SYNC_TREE; | 494 return ACTION_ACTIVATE_SYNC_TREE; |
475 if (ShouldCommit()) | 495 if (ShouldCommit()) |
476 return ACTION_COMMIT; | 496 return ACTION_COMMIT; |
477 if (ShouldAnimate()) | 497 if (ShouldAnimate()) |
478 return ACTION_ANIMATE; | 498 return ACTION_ANIMATE; |
479 if (ShouldDraw()) { | 499 if (ShouldDraw()) { |
480 if (PendingDrawsShouldBeAborted()) | 500 if (PendingDrawsShouldBeAborted()) |
481 return ACTION_DRAW_AND_SWAP_ABORT; | 501 return ACTION_DRAW_AND_SWAP_ABORT; |
482 else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) | 502 else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) |
483 return ACTION_DRAW_AND_SWAP_FORCED; | 503 return ACTION_DRAW_AND_SWAP_FORCED; |
484 else | 504 else |
485 return ACTION_DRAW_AND_SWAP_IF_POSSIBLE; | 505 return ACTION_DRAW_AND_SWAP_IF_POSSIBLE; |
486 } | 506 } |
487 if (ShouldPrepareTiles()) | 507 if (ShouldPrepareTiles()) |
488 return ACTION_PREPARE_TILES; | 508 return ACTION_PREPARE_TILES; |
489 if (ShouldSendBeginMainFrame()) | 509 if (ShouldSendBeginMainFrame()) |
490 return ACTION_SEND_BEGIN_MAIN_FRAME; | 510 return ACTION_SEND_BEGIN_MAIN_FRAME; |
| 511 if (ShouldInvalidateOutputSurface()) |
| 512 return ACTION_INVALIDATE_OUTPUT_SURFACE; |
491 if (ShouldBeginOutputSurfaceCreation()) | 513 if (ShouldBeginOutputSurfaceCreation()) |
492 return ACTION_BEGIN_OUTPUT_SURFACE_CREATION; | 514 return ACTION_BEGIN_OUTPUT_SURFACE_CREATION; |
493 return ACTION_NONE; | 515 return ACTION_NONE; |
494 } | 516 } |
495 | 517 |
496 void SchedulerStateMachine::UpdateState(Action action) { | 518 void SchedulerStateMachine::UpdateState(Action action) { |
497 switch (action) { | 519 switch (action) { |
498 case ACTION_NONE: | 520 case ACTION_NONE: |
499 return; | 521 return; |
500 | 522 |
501 case ACTION_ACTIVATE_SYNC_TREE: | 523 case ACTION_ACTIVATE_SYNC_TREE: |
502 UpdateStateOnActivation(); | 524 UpdateStateOnActivation(); |
503 return; | 525 return; |
504 | 526 |
505 case ACTION_ANIMATE: | 527 case ACTION_ANIMATE: |
506 DCHECK(!animate_funnel_); | 528 UpdateStateOnAnimate(); |
507 last_frame_number_animate_performed_ = current_frame_number_; | |
508 animate_funnel_ = true; | |
509 needs_animate_ = false; | |
510 // TODO(skyostil): Instead of assuming this, require the client to tell | |
511 // us. | |
512 SetNeedsRedraw(); | |
513 return; | 529 return; |
514 | 530 |
515 case ACTION_SEND_BEGIN_MAIN_FRAME: | 531 case ACTION_SEND_BEGIN_MAIN_FRAME: |
516 DCHECK(!has_pending_tree_ || | 532 UpdateStateOnSendBeginMainFrame(); |
517 settings_.main_frame_before_activation_enabled); | |
518 DCHECK(visible_); | |
519 DCHECK(!send_begin_main_frame_funnel_); | |
520 commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT; | |
521 needs_commit_ = false; | |
522 send_begin_main_frame_funnel_ = true; | |
523 last_frame_number_begin_main_frame_sent_ = | |
524 current_frame_number_; | |
525 return; | 533 return; |
526 | 534 |
527 case ACTION_COMMIT: { | 535 case ACTION_COMMIT: { |
528 bool commit_has_no_updates = false; | 536 bool commit_has_no_updates = false; |
529 UpdateStateOnCommit(commit_has_no_updates); | 537 UpdateStateOnCommit(commit_has_no_updates); |
530 return; | 538 return; |
531 } | 539 } |
532 | 540 |
533 case ACTION_DRAW_AND_SWAP_FORCED: | 541 case ACTION_DRAW_AND_SWAP_FORCED: |
534 case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: { | 542 case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: { |
535 bool did_request_swap = true; | 543 bool did_request_swap = true; |
536 UpdateStateOnDraw(did_request_swap); | 544 UpdateStateOnDraw(did_request_swap); |
537 return; | 545 return; |
538 } | 546 } |
539 | 547 |
540 case ACTION_DRAW_AND_SWAP_ABORT: { | 548 case ACTION_DRAW_AND_SWAP_ABORT: { |
541 bool did_request_swap = false; | 549 bool did_request_swap = false; |
542 UpdateStateOnDraw(did_request_swap); | 550 UpdateStateOnDraw(did_request_swap); |
543 return; | 551 return; |
544 } | 552 } |
545 | 553 |
546 case ACTION_BEGIN_OUTPUT_SURFACE_CREATION: | 554 case ACTION_BEGIN_OUTPUT_SURFACE_CREATION: |
547 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST); | 555 UpdateStateOnBeginOutputSurfaceCreation(); |
548 output_surface_state_ = OUTPUT_SURFACE_CREATING; | |
549 | |
550 // The following DCHECKs make sure we are in the proper quiescent state. | |
551 // The pipeline should be flushed entirely before we start output | |
552 // surface creation to avoid complicated corner cases. | |
553 DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE); | |
554 DCHECK(!has_pending_tree_); | |
555 DCHECK(!active_tree_needs_first_draw_); | |
556 return; | 556 return; |
557 | 557 |
558 case ACTION_PREPARE_TILES: | 558 case ACTION_PREPARE_TILES: |
559 UpdateStateOnPrepareTiles(); | 559 UpdateStateOnPrepareTiles(); |
560 return; | 560 return; |
| 561 |
| 562 case ACTION_INVALIDATE_OUTPUT_SURFACE: |
| 563 UpdateStateOnInvalidateOutputSurface(); |
| 564 return; |
561 } | 565 } |
562 } | 566 } |
563 | 567 |
| 568 void SchedulerStateMachine::UpdateStateOnAnimate() { |
| 569 DCHECK(!animate_funnel_); |
| 570 last_frame_number_animate_performed_ = current_frame_number_; |
| 571 animate_funnel_ = true; |
| 572 needs_animate_ = false; |
| 573 // TODO(skyostil): Instead of assuming this, require the client to tell |
| 574 // us. |
| 575 SetNeedsRedraw(); |
| 576 } |
| 577 |
| 578 void SchedulerStateMachine::UpdateStateOnSendBeginMainFrame() { |
| 579 DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled); |
| 580 DCHECK(visible_); |
| 581 DCHECK(!send_begin_main_frame_funnel_); |
| 582 commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT; |
| 583 needs_commit_ = false; |
| 584 send_begin_main_frame_funnel_ = true; |
| 585 last_frame_number_begin_main_frame_sent_ = current_frame_number_; |
| 586 } |
| 587 |
564 void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { | 588 void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { |
565 commit_count_++; | 589 commit_count_++; |
566 | 590 |
567 if (!commit_has_no_updates) | 591 if (!commit_has_no_updates) |
568 animate_funnel_ = false; | 592 animate_funnel_ = false; |
569 | 593 |
570 if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) { | 594 if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) { |
571 commit_state_ = COMMIT_STATE_IDLE; | 595 commit_state_ = COMMIT_STATE_IDLE; |
572 } else if (settings_.impl_side_painting) { | 596 } else if (settings_.impl_side_painting) { |
573 commit_state_ = COMMIT_STATE_WAITING_FOR_ACTIVATION; | 597 commit_state_ = COMMIT_STATE_WAITING_FOR_ACTIVATION; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
648 DCHECK(!request_swap_funnel_); | 672 DCHECK(!request_swap_funnel_); |
649 request_swap_funnel_ = true; | 673 request_swap_funnel_ = true; |
650 last_frame_number_swap_requested_ = current_frame_number_; | 674 last_frame_number_swap_requested_ = current_frame_number_; |
651 } | 675 } |
652 } | 676 } |
653 | 677 |
654 void SchedulerStateMachine::UpdateStateOnPrepareTiles() { | 678 void SchedulerStateMachine::UpdateStateOnPrepareTiles() { |
655 needs_prepare_tiles_ = false; | 679 needs_prepare_tiles_ = false; |
656 } | 680 } |
657 | 681 |
| 682 void SchedulerStateMachine::UpdateStateOnBeginOutputSurfaceCreation() { |
| 683 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST); |
| 684 output_surface_state_ = OUTPUT_SURFACE_CREATING; |
| 685 |
| 686 // The following DCHECKs make sure we are in the proper quiescent state. |
| 687 // The pipeline should be flushed entirely before we start output |
| 688 // surface creation to avoid complicated corner cases. |
| 689 DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE); |
| 690 DCHECK(!has_pending_tree_); |
| 691 DCHECK(!active_tree_needs_first_draw_); |
| 692 } |
| 693 |
| 694 void SchedulerStateMachine::UpdateStateOnInvalidateOutputSurface() { |
| 695 DCHECK(!invalidate_output_surface_funnel_); |
| 696 invalidate_output_surface_funnel_ = true; |
| 697 last_frame_number_invalidate_output_surface_performed_ = |
| 698 current_frame_number_; |
| 699 // There is no guarantee that a draw will arrive from the synchronous |
| 700 // compositor. We clear this flag here so that the pipeline isn't blocked. |
| 701 active_tree_needs_first_draw_ = false; |
| 702 } |
| 703 |
658 void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() { | 704 void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() { |
659 TRACE_EVENT_INSTANT0("cc", | 705 TRACE_EVENT_INSTANT0("cc", |
660 "Scheduler: SkipNextBeginMainFrameToReduceLatency", | 706 "Scheduler: SkipNextBeginMainFrameToReduceLatency", |
661 TRACE_EVENT_SCOPE_THREAD); | 707 TRACE_EVENT_SCOPE_THREAD); |
662 skip_next_begin_main_frame_to_reduce_latency_ = true; | 708 skip_next_begin_main_frame_to_reduce_latency_ = true; |
663 } | 709 } |
664 | 710 |
665 bool SchedulerStateMachine::BeginFrameNeededForChildren() const { | 711 bool SchedulerStateMachine::BeginFrameNeededForChildren() const { |
666 if (HasInitializedOutputSurface()) | 712 if (HasInitializedOutputSurface()) |
667 return children_need_begin_frames_; | 713 return children_need_begin_frames_; |
668 | 714 |
669 return false; | 715 return false; |
670 } | 716 } |
671 | 717 |
672 bool SchedulerStateMachine::BeginFrameNeeded() const { | 718 bool SchedulerStateMachine::BeginFrameNeeded() const { |
673 // We can't handle BeginFrames when output surface isn't initialized. | 719 // We can't handle BeginFrames when output surface isn't initialized. |
674 // TODO(brianderson): Support output surface creation inside a BeginFrame. | 720 // TODO(brianderson): Support output surface creation inside a BeginFrame. |
675 if (!HasInitializedOutputSurface()) | 721 if (!HasInitializedOutputSurface()) |
676 return false; | 722 return false; |
677 | 723 return (BeginFrameNeededToAnimateOrDraw() || BeginFrameNeededForChildren() || |
678 if (SupportsProactiveBeginFrame()) { | 724 ProactiveBeginFrameWanted()); |
679 return (BeginFrameNeededToAnimateOrDraw() || | |
680 BeginFrameNeededForChildren() || | |
681 ProactiveBeginFrameWanted()); | |
682 } | |
683 | |
684 // Proactive BeginFrames are bad for the synchronous compositor because we | |
685 // have to draw when we get the BeginFrame and could end up drawing many | |
686 // duplicate frames if our new frame isn't ready in time. | |
687 // To poll for state with the synchronous compositor without having to draw, | |
688 // we rely on ShouldPollForAnticipatedDrawTriggers instead. | |
689 // Synchronous compositor doesn't have a browser. | |
690 DCHECK(!children_need_begin_frames_); | |
691 return BeginFrameNeededToAnimateOrDraw(); | |
692 } | |
693 | |
694 bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const { | |
695 // ShouldPollForAnticipatedDrawTriggers is what we use in place of | |
696 // ProactiveBeginFrameWanted when we are using the synchronous | |
697 // compositor. | |
698 if (!SupportsProactiveBeginFrame()) { | |
699 return !BeginFrameNeededToAnimateOrDraw() && ProactiveBeginFrameWanted(); | |
700 } | |
701 | |
702 // Non synchronous compositors should rely on | |
703 // ProactiveBeginFrameWanted to poll for state instead. | |
704 return false; | |
705 } | |
706 | |
707 // Note: If SupportsProactiveBeginFrame is false, the scheduler should poll | |
708 // for changes in it's draw state so it can request a BeginFrame when it's | |
709 // actually ready. | |
710 bool SchedulerStateMachine::SupportsProactiveBeginFrame() const { | |
711 // It is undesirable to proactively request BeginFrames if we are | |
712 // using a synchronous compositor because we *must* draw for every | |
713 // BeginFrame, which could cause duplicate draws. | |
714 return !settings_.using_synchronous_renderer_compositor; | |
715 } | 725 } |
716 | 726 |
717 void SchedulerStateMachine::SetChildrenNeedBeginFrames( | 727 void SchedulerStateMachine::SetChildrenNeedBeginFrames( |
718 bool children_need_begin_frames) { | 728 bool children_need_begin_frames) { |
719 children_need_begin_frames_ = children_need_begin_frames; | 729 children_need_begin_frames_ = children_need_begin_frames; |
720 } | 730 } |
721 | 731 |
722 void SchedulerStateMachine::SetDeferCommits(bool defer_commits) { | 732 void SchedulerStateMachine::SetDeferCommits(bool defer_commits) { |
723 defer_commits_ = defer_commits; | 733 defer_commits_ = defer_commits; |
724 } | 734 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
763 // SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame | 773 // SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame |
764 // provider and get sampled at an inopportune time, delaying the next | 774 // provider and get sampled at an inopportune time, delaying the next |
765 // BeginImplFrame. | 775 // BeginImplFrame. |
766 if (request_swap_funnel_) | 776 if (request_swap_funnel_) |
767 return true; | 777 return true; |
768 | 778 |
769 return false; | 779 return false; |
770 } | 780 } |
771 | 781 |
772 void SchedulerStateMachine::OnBeginImplFrame() { | 782 void SchedulerStateMachine::OnBeginImplFrame() { |
773 AdvanceCurrentFrameNumber(); | |
774 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) | |
775 << AsValue()->ToString(); | |
776 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING; | 783 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING; |
| 784 |
| 785 current_frame_number_++; |
| 786 |
| 787 // Clear funnels for any actions we perform during the frame. |
| 788 animate_funnel_ = false; |
| 789 perform_swap_funnel_ = false; |
| 790 request_swap_funnel_ = false; |
| 791 send_begin_main_frame_funnel_ = false; |
| 792 invalidate_output_surface_funnel_ = false; |
| 793 |
| 794 skip_begin_main_frame_to_reduce_latency_ = |
| 795 skip_next_begin_main_frame_to_reduce_latency_; |
| 796 skip_next_begin_main_frame_to_reduce_latency_ = false; |
777 } | 797 } |
778 | 798 |
779 void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() { | 799 void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() { |
780 DCHECK_EQ(begin_impl_frame_state_, | |
781 BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) | |
782 << AsValue()->ToString(); | |
783 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME; | 800 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME; |
784 } | 801 } |
785 | 802 |
786 void SchedulerStateMachine::OnBeginImplFrameDeadline() { | 803 void SchedulerStateMachine::OnBeginImplFrameDeadline() { |
787 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) | |
788 << AsValue()->ToString(); | |
789 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; | 804 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; |
| 805 |
| 806 // Clear funnels for any actions we perform during the deadline. |
| 807 perform_swap_funnel_ = false; |
| 808 request_swap_funnel_ = false; |
| 809 invalidate_output_surface_funnel_ = false; |
| 810 |
| 811 // "Drain" the PrepareTiles funnel. |
| 812 if (prepare_tiles_funnel_ > 0) |
| 813 prepare_tiles_funnel_--; |
790 } | 814 } |
791 | 815 |
792 void SchedulerStateMachine::OnBeginImplFrameIdle() { | 816 void SchedulerStateMachine::OnBeginImplFrameIdle() { |
793 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) | |
794 << AsValue()->ToString(); | |
795 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE; | 817 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE; |
796 } | 818 } |
797 | 819 |
798 SchedulerStateMachine::BeginImplFrameDeadlineMode | 820 SchedulerStateMachine::BeginImplFrameDeadlineMode |
799 SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { | 821 SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { |
800 if (ShouldTriggerBeginImplFrameDeadlineImmediately()) { | 822 if (settings_.using_synchronous_renderer_compositor) { |
| 823 // No deadline for synchronous compositor. |
| 824 return BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE; |
| 825 } else if (ShouldTriggerBeginImplFrameDeadlineImmediately()) { |
801 return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE; | 826 return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE; |
802 } else if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) { | 827 } else if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) { |
803 // We have an animation or fast input path on the impl thread that wants | 828 // We have an animation or fast input path on the impl thread that wants |
804 // to draw, so don't wait too long for a new active tree. | 829 // to draw, so don't wait too long for a new active tree. |
805 // If we are swap throttled we should wait until we are unblocked. | 830 // If we are swap throttled we should wait until we are unblocked. |
806 return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR; | 831 return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR; |
807 } else { | 832 } else { |
808 // The impl thread doesn't have anything it wants to draw and we are just | 833 // The impl thread doesn't have anything it wants to draw and we are just |
809 // waiting for a new active tree or we are swap throttled. In short we are | 834 // waiting for a new active tree or we are swap throttled. In short we are |
810 // blocked. | 835 // blocked. |
811 return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE; | 836 return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE; |
812 } | 837 } |
813 } | 838 } |
814 | 839 |
815 bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately() | 840 bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately() |
816 const { | 841 const { |
817 // TODO(brianderson): This should take into account multiple commit sources. | 842 // TODO(brianderson): This should take into account multiple commit sources. |
818 | |
819 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) | 843 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) |
820 return false; | 844 return false; |
821 | 845 |
822 // If we've lost the output surface, end the current BeginImplFrame ASAP | 846 // If we've lost the output surface, end the current BeginImplFrame ASAP |
823 // so we can start creating the next output surface. | 847 // so we can start creating the next output surface. |
824 if (output_surface_state_ == OUTPUT_SURFACE_LOST) | 848 if (output_surface_state_ == OUTPUT_SURFACE_LOST) |
825 return true; | 849 return true; |
826 | 850 |
827 // SwapAck throttle the deadline since we wont draw and swap anyway. | 851 // SwapAck throttle the deadline since we wont draw and swap anyway. |
828 if (pending_swaps_ >= max_pending_swaps_) | 852 if (pending_swaps_ >= max_pending_swaps_) |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
883 // which case the main thread is in a high latency mode. | 907 // which case the main thread is in a high latency mode. |
884 return (active_tree_needs_first_draw_ || perform_swap_funnel_) && | 908 return (active_tree_needs_first_draw_ || perform_swap_funnel_) && |
885 !send_begin_main_frame_funnel_; | 909 !send_begin_main_frame_funnel_; |
886 } | 910 } |
887 | 911 |
888 // If the active tree needs its first draw in any other state, we know the | 912 // If the active tree needs its first draw in any other state, we know the |
889 // main thread is in a high latency mode. | 913 // main thread is in a high latency mode. |
890 return active_tree_needs_first_draw_; | 914 return active_tree_needs_first_draw_; |
891 } | 915 } |
892 | 916 |
893 void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() { | |
894 AdvanceCurrentFrameNumber(); | |
895 inside_poll_for_anticipated_draw_triggers_ = true; | |
896 } | |
897 | |
898 void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() { | |
899 inside_poll_for_anticipated_draw_triggers_ = false; | |
900 } | |
901 | |
902 void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; } | 917 void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; } |
903 | 918 |
904 void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; } | 919 void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; } |
905 | 920 |
906 void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; } | 921 void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; } |
907 | 922 |
908 void SchedulerStateMachine::SetNeedsAnimate() { | 923 void SchedulerStateMachine::SetNeedsAnimate() { |
909 needs_animate_ = true; | 924 needs_animate_ = true; |
910 } | 925 } |
911 | 926 |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1072 static_cast<int>(begin_impl_frame_state_), | 1087 static_cast<int>(begin_impl_frame_state_), |
1073 static_cast<int>(commit_state_), | 1088 static_cast<int>(commit_state_), |
1074 has_pending_tree_ ? 'T' : 'F', | 1089 has_pending_tree_ ? 'T' : 'F', |
1075 pending_tree_is_ready_for_activation_ ? 'T' : 'F', | 1090 pending_tree_is_ready_for_activation_ ? 'T' : 'F', |
1076 active_tree_needs_first_draw_ ? 'T' : 'F', | 1091 active_tree_needs_first_draw_ ? 'T' : 'F', |
1077 max_pending_swaps_, | 1092 max_pending_swaps_, |
1078 pending_swaps_); | 1093 pending_swaps_); |
1079 } | 1094 } |
1080 | 1095 |
1081 } // namespace cc | 1096 } // namespace cc |
OLD | NEW |