This source file includes following definitions.
- needs_back_to_back_readback_
- OutputSurfaceStateToString
- BeginImplFrameStateToString
- CommitStateToString
- TextureStateToString
- SynchronousReadbackStateToString
- ForcedRedrawOnTimeoutStateToString
- ActionToString
- AsValue
- AdvanceCurrentFrameNumber
- HasSentBeginMainFrameThisFrame
- HasUpdatedVisibleTilesThisFrame
- HasSwappedThisFrame
- PendingDrawsShouldBeAborted
- PendingActivationsShouldBeForced
- ShouldBeginOutputSurfaceCreation
- ShouldDraw
- ShouldAcquireLayerTexturesForMainThread
- ShouldActivatePendingTree
- ShouldUpdateVisibleTiles
- ShouldSendBeginMainFrame
- ShouldCommit
- ShouldManageTiles
- NextAction
- CheckInvariants
- UpdateState
- UpdateStateOnCommit
- UpdateStateOnActivation
- UpdateStateOnDraw
- UpdateStateOnManageTiles
- SetMainThreadNeedsLayerTextures
- SetSkipNextBeginMainFrameToReduceLatency
- BeginImplFrameNeeded
- ShouldPollForAnticipatedDrawTriggers
- SupportsProactiveBeginImplFrame
- BeginImplFrameNeededToDraw
- ProactiveBeginImplFrameWanted
- OnBeginImplFrame
- OnBeginImplFrameDeadlinePending
- OnBeginImplFrameDeadline
- OnBeginImplFrameIdle
- ShouldTriggerBeginImplFrameDeadlineEarly
- MainThreadIsInHighLatencyMode
- DidEnterPollForAnticipatedDrawTriggers
- DidLeavePollForAnticipatedDrawTriggers
- SetVisible
- SetCanDraw
- SetNeedsRedraw
- SetNeedsManageTiles
- SetSwapUsedIncompleteTile
- SetSmoothnessTakesPriority
- DidDrawIfPossibleCompleted
- SetNeedsCommit
- SetNeedsForcedCommitForReadback
- NotifyReadyToCommit
- BeginMainFrameAborted
- DidManageTiles
- DidLoseOutputSurface
- NotifyReadyToActivate
- DidCreateAndInitializeOutputSurface
- NotifyBeginMainFrameStarted
- HasInitializedOutputSurface
#include "cc/scheduler/scheduler_state_machine.h"
#include "base/debug/trace_event.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "ui/gfx/frame_time.h"
namespace cc {
SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
: settings_(settings),
output_surface_state_(OUTPUT_SURFACE_LOST),
begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE),
commit_state_(COMMIT_STATE_IDLE),
texture_state_(LAYER_TEXTURE_STATE_UNLOCKED),
forced_redraw_state_(FORCED_REDRAW_STATE_IDLE),
readback_state_(READBACK_STATE_IDLE),
commit_count_(0),
current_frame_number_(0),
last_frame_number_swap_performed_(-1),
last_frame_number_begin_main_frame_sent_(-1),
last_frame_number_update_visible_tiles_was_called_(-1),
manage_tiles_funnel_(0),
consecutive_checkerboard_animations_(0),
needs_redraw_(false),
needs_manage_tiles_(false),
swap_used_incomplete_tile_(false),
needs_commit_(false),
main_thread_needs_layer_textures_(false),
inside_poll_for_anticipated_draw_triggers_(false),
visible_(false),
can_start_(false),
can_draw_(false),
has_pending_tree_(false),
pending_tree_is_ready_for_activation_(false),
active_tree_needs_first_draw_(false),
draw_if_possible_failed_(false),
did_create_and_initialize_first_output_surface_(false),
smoothness_takes_priority_(false),
skip_next_begin_main_frame_to_reduce_latency_(false),
skip_begin_main_frame_to_reduce_latency_(false),
continuous_painting_(false),
needs_back_to_back_readback_(false) {}
const char* SchedulerStateMachine::OutputSurfaceStateToString(
OutputSurfaceState state) {
switch (state) {
case OUTPUT_SURFACE_ACTIVE:
return "OUTPUT_SURFACE_ACTIVE";
case OUTPUT_SURFACE_LOST:
return "OUTPUT_SURFACE_LOST";
case OUTPUT_SURFACE_CREATING:
return "OUTPUT_SURFACE_CREATING";
case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT:
return "OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT";
case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION:
return "OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION";
}
NOTREACHED();
return "???";
}
const char* SchedulerStateMachine::BeginImplFrameStateToString(
BeginImplFrameState state) {
switch (state) {
case BEGIN_IMPL_FRAME_STATE_IDLE:
return "BEGIN_IMPL_FRAME_STATE_IDLE";
case BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING:
return "BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING";
case BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME:
return "BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME";
case BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE:
return "BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE";
}
NOTREACHED();
return "???";
}
const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
switch (state) {
case COMMIT_STATE_IDLE:
return "COMMIT_STATE_IDLE";
case COMMIT_STATE_BEGIN_MAIN_FRAME_SENT:
return "COMMIT_STATE_BEGIN_MAIN_FRAME_SENT";
case COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED:
return "COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED";
case COMMIT_STATE_READY_TO_COMMIT:
return "COMMIT_STATE_READY_TO_COMMIT";
case COMMIT_STATE_WAITING_FOR_ACTIVATION:
return "COMMIT_STATE_WAITING_FOR_ACTIVATION";
case COMMIT_STATE_WAITING_FOR_FIRST_DRAW:
return "COMMIT_STATE_WAITING_FOR_FIRST_DRAW";
}
NOTREACHED();
return "???";
}
const char* SchedulerStateMachine::TextureStateToString(TextureState state) {
switch (state) {
case LAYER_TEXTURE_STATE_UNLOCKED:
return "LAYER_TEXTURE_STATE_UNLOCKED";
case LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD:
return "LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD";
case LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD:
return "LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD";
}
NOTREACHED();
return "???";
}
const char* SchedulerStateMachine::SynchronousReadbackStateToString(
SynchronousReadbackState state) {
switch (state) {
case READBACK_STATE_IDLE:
return "READBACK_STATE_IDLE";
case READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME:
return "READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME";
case READBACK_STATE_WAITING_FOR_COMMIT:
return "READBACK_STATE_WAITING_FOR_COMMIT";
case READBACK_STATE_WAITING_FOR_ACTIVATION:
return "READBACK_STATE_WAITING_FOR_ACTIVATION";
case READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK:
return "READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK";
case READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT:
return "READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT";
case READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION:
return "READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION";
}
NOTREACHED();
return "???";
}
const char* SchedulerStateMachine::ForcedRedrawOnTimeoutStateToString(
ForcedRedrawOnTimeoutState state) {
switch (state) {
case FORCED_REDRAW_STATE_IDLE:
return "FORCED_REDRAW_STATE_IDLE";
case FORCED_REDRAW_STATE_WAITING_FOR_COMMIT:
return "FORCED_REDRAW_STATE_WAITING_FOR_COMMIT";
case FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION:
return "FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION";
case FORCED_REDRAW_STATE_WAITING_FOR_DRAW:
return "FORCED_REDRAW_STATE_WAITING_FOR_DRAW";
}
NOTREACHED();
return "???";
}
const char* SchedulerStateMachine::ActionToString(Action action) {
switch (action) {
case ACTION_NONE:
return "ACTION_NONE";
case ACTION_SEND_BEGIN_MAIN_FRAME:
return "ACTION_SEND_BEGIN_MAIN_FRAME";
case ACTION_COMMIT:
return "ACTION_COMMIT";
case ACTION_UPDATE_VISIBLE_TILES:
return "ACTION_UPDATE_VISIBLE_TILES";
case ACTION_ACTIVATE_PENDING_TREE:
return "ACTION_ACTIVATE_PENDING_TREE";
case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
return "ACTION_DRAW_AND_SWAP_IF_POSSIBLE";
case ACTION_DRAW_AND_SWAP_FORCED:
return "ACTION_DRAW_AND_SWAP_FORCED";
case ACTION_DRAW_AND_SWAP_ABORT:
return "ACTION_DRAW_AND_SWAP_ABORT";
case ACTION_DRAW_AND_READBACK:
return "ACTION_DRAW_AND_READBACK";
case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION";
case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
return "ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD";
case ACTION_MANAGE_TILES:
return "ACTION_MANAGE_TILES";
}
NOTREACHED();
return "???";
}
scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
scoped_ptr<base::DictionaryValue> major_state(new base::DictionaryValue);
major_state->SetString("next_action", ActionToString(NextAction()));
major_state->SetString("begin_impl_frame_state",
BeginImplFrameStateToString(begin_impl_frame_state_));
major_state->SetString("commit_state", CommitStateToString(commit_state_));
major_state->SetString("texture_state_",
TextureStateToString(texture_state_));
major_state->SetString("output_surface_state_",
OutputSurfaceStateToString(output_surface_state_));
major_state->SetString(
"forced_redraw_state",
ForcedRedrawOnTimeoutStateToString(forced_redraw_state_));
major_state->SetString("readback_state",
SynchronousReadbackStateToString(readback_state_));
state->Set("major_state", major_state.release());
scoped_ptr<base::DictionaryValue> timestamps_state(new base::DictionaryValue);
base::TimeTicks now = gfx::FrameTime::Now();
timestamps_state->SetDouble(
"0_interval",
last_begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L);
timestamps_state->SetDouble(
"1_now_to_deadline",
(last_begin_impl_frame_args_.deadline - now).InMicroseconds() / 1000.0L);
timestamps_state->SetDouble(
"2_frame_time_to_now",
(now - last_begin_impl_frame_args_.frame_time).InMicroseconds() /
1000.0L);
timestamps_state->SetDouble(
"3_frame_time_to_deadline",
(last_begin_impl_frame_args_.deadline -
last_begin_impl_frame_args_.frame_time).InMicroseconds() /
1000.0L);
timestamps_state->SetDouble(
"4_now", (now - base::TimeTicks()).InMicroseconds() / 1000.0L);
timestamps_state->SetDouble(
"5_frame_time",
(last_begin_impl_frame_args_.frame_time - base::TimeTicks())
.InMicroseconds() /
1000.0L);
timestamps_state->SetDouble(
"6_deadline",
(last_begin_impl_frame_args_.deadline - base::TimeTicks())
.InMicroseconds() /
1000.0L);
state->Set("major_timestamps_in_ms", timestamps_state.release());
scoped_ptr<base::DictionaryValue> minor_state(new base::DictionaryValue);
minor_state->SetInteger("commit_count", commit_count_);
minor_state->SetInteger("current_frame_number", current_frame_number_);
minor_state->SetInteger("last_frame_number_swap_performed",
last_frame_number_swap_performed_);
minor_state->SetInteger(
"last_frame_number_begin_main_frame_sent",
last_frame_number_begin_main_frame_sent_);
minor_state->SetInteger(
"last_frame_number_update_visible_tiles_was_called",
last_frame_number_update_visible_tiles_was_called_);
minor_state->SetInteger("manage_tiles_funnel", manage_tiles_funnel_);
minor_state->SetInteger("consecutive_checkerboard_animations",
consecutive_checkerboard_animations_);
minor_state->SetBoolean("needs_redraw", needs_redraw_);
minor_state->SetBoolean("needs_manage_tiles", needs_manage_tiles_);
minor_state->SetBoolean("swap_used_incomplete_tile",
swap_used_incomplete_tile_);
minor_state->SetBoolean("needs_commit", needs_commit_);
minor_state->SetBoolean("main_thread_needs_layer_textures",
main_thread_needs_layer_textures_);
minor_state->SetBoolean("visible", visible_);
minor_state->SetBoolean("can_start", can_start_);
minor_state->SetBoolean("can_draw", can_draw_);
minor_state->SetBoolean("has_pending_tree", has_pending_tree_);
minor_state->SetBoolean("pending_tree_is_ready_for_activation",
pending_tree_is_ready_for_activation_);
minor_state->SetBoolean("active_tree_needs_first_draw",
active_tree_needs_first_draw_);
minor_state->SetBoolean("draw_if_possible_failed", draw_if_possible_failed_);
minor_state->SetBoolean("did_create_and_initialize_first_output_surface",
did_create_and_initialize_first_output_surface_);
minor_state->SetBoolean("smoothness_takes_priority",
smoothness_takes_priority_);
minor_state->SetBoolean("main_thread_is_in_high_latency_mode",
MainThreadIsInHighLatencyMode());
minor_state->SetBoolean("skip_begin_main_frame_to_reduce_latency",
skip_begin_main_frame_to_reduce_latency_);
minor_state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency",
skip_next_begin_main_frame_to_reduce_latency_);
minor_state->SetBoolean("continuous_painting", continuous_painting_);
state->Set("minor_state", minor_state.release());
return state.PassAs<base::Value>();
}
void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
current_frame_number_++;
if (manage_tiles_funnel_ > 0)
manage_tiles_funnel_--;
skip_begin_main_frame_to_reduce_latency_ =
skip_next_begin_main_frame_to_reduce_latency_;
skip_next_begin_main_frame_to_reduce_latency_ = false;
}
bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const {
return current_frame_number_ ==
last_frame_number_begin_main_frame_sent_;
}
bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
return current_frame_number_ ==
last_frame_number_update_visible_tiles_was_called_;
}
bool SchedulerStateMachine::HasSwappedThisFrame() const {
return current_frame_number_ == last_frame_number_swap_performed_;
}
bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
if (PendingActivationsShouldBeForced())
return true;
if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD)
return true;
if (!can_draw_)
return true;
if (!visible_)
return true;
return false;
}
bool SchedulerStateMachine::PendingActivationsShouldBeForced() const {
if (output_surface_state_ == OUTPUT_SURFACE_LOST)
return true;
return false;
}
bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
if (!can_start_)
return false;
if (commit_state_ != COMMIT_STATE_IDLE)
return false;
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE)
return false;
if (active_tree_needs_first_draw_ || has_pending_tree_)
return false;
return output_surface_state_ == OUTPUT_SURFACE_LOST;
}
bool SchedulerStateMachine::ShouldDraw() const {
if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT ||
readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
return false;
if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK)
return true;
if (PendingDrawsShouldBeAborted())
return active_tree_needs_first_draw_;
if (HasSwappedThisFrame())
return false;
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
return false;
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
return true;
return needs_redraw_;
}
bool SchedulerStateMachine::ShouldAcquireLayerTexturesForMainThread() const {
if (!main_thread_needs_layer_textures_)
return false;
if (texture_state_ == LAYER_TEXTURE_STATE_UNLOCKED)
return true;
DCHECK_EQ(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD);
return false;
}
bool SchedulerStateMachine::ShouldActivatePendingTree() const {
if (!has_pending_tree_)
return false;
if (active_tree_needs_first_draw_)
return false;
if (PendingActivationsShouldBeForced())
return true;
return pending_tree_is_ready_for_activation_;
}
bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
if (!settings_.impl_side_painting)
return false;
if (HasUpdatedVisibleTilesThisFrame())
return false;
if (!HasInitializedOutputSurface())
return false;
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
return false;
if (swap_used_incomplete_tile_)
return true;
return false;
}
bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (!needs_commit_)
return false;
if (commit_state_ != COMMIT_STATE_IDLE)
return false;
if (smoothness_takes_priority_ &&
(has_pending_tree_ || active_tree_needs_first_draw_)) {
return false;
}
if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME)
return !CommitPending();
if (!visible_)
return false;
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT)
return true;
if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_IDLE &&
BeginImplFrameNeeded())
return false;
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
return true;
if (HasSentBeginMainFrameThisFrame())
return false;
if (!HasInitializedOutputSurface())
return false;
if (skip_begin_main_frame_to_reduce_latency_)
return false;
return true;
}
bool SchedulerStateMachine::ShouldCommit() const {
if (commit_state_ != COMMIT_STATE_READY_TO_COMMIT)
return false;
if (has_pending_tree_) {
DCHECK(settings_.main_frame_before_activation_enabled);
return false;
}
if (active_tree_needs_first_draw_)
return false;
return true;
}
bool SchedulerStateMachine::ShouldManageTiles() const {
if (manage_tiles_funnel_ > 0)
return false;
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
!inside_poll_for_anticipated_draw_triggers_)
return false;
return needs_manage_tiles_;
}
SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
if (ShouldAcquireLayerTexturesForMainThread())
return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD;
if (ShouldUpdateVisibleTiles())
return ACTION_UPDATE_VISIBLE_TILES;
if (ShouldActivatePendingTree())
return ACTION_ACTIVATE_PENDING_TREE;
if (ShouldCommit())
return ACTION_COMMIT;
if (ShouldDraw()) {
if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK)
return ACTION_DRAW_AND_READBACK;
else if (PendingDrawsShouldBeAborted())
return ACTION_DRAW_AND_SWAP_ABORT;
else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
return ACTION_DRAW_AND_SWAP_FORCED;
else
return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
}
if (ShouldManageTiles())
return ACTION_MANAGE_TILES;
if (ShouldSendBeginMainFrame())
return ACTION_SEND_BEGIN_MAIN_FRAME;
if (ShouldBeginOutputSurfaceCreation())
return ACTION_BEGIN_OUTPUT_SURFACE_CREATION;
return ACTION_NONE;
}
void SchedulerStateMachine::CheckInvariants() {
DCHECK(!(forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW &&
readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK));
if (has_pending_tree_ || active_tree_needs_first_draw_)
DCHECK(texture_state_ != LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD);
}
void SchedulerStateMachine::UpdateState(Action action) {
switch (action) {
case ACTION_NONE:
return;
case ACTION_UPDATE_VISIBLE_TILES:
last_frame_number_update_visible_tiles_was_called_ =
current_frame_number_;
return;
case ACTION_ACTIVATE_PENDING_TREE:
UpdateStateOnActivation();
return;
case ACTION_SEND_BEGIN_MAIN_FRAME:
DCHECK(!has_pending_tree_ ||
settings_.main_frame_before_activation_enabled);
DCHECK(!active_tree_needs_first_draw_ ||
settings_.main_frame_before_draw_enabled);
DCHECK(visible_ ||
readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME);
commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
needs_commit_ = false;
if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME)
readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT;
last_frame_number_begin_main_frame_sent_ =
current_frame_number_;
return;
case ACTION_COMMIT: {
bool commit_was_aborted = false;
UpdateStateOnCommit(commit_was_aborted);
return;
}
case ACTION_DRAW_AND_SWAP_FORCED:
case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
bool did_swap = true;
UpdateStateOnDraw(did_swap);
return;
}
case ACTION_DRAW_AND_SWAP_ABORT:
case ACTION_DRAW_AND_READBACK: {
bool did_swap = false;
UpdateStateOnDraw(did_swap);
return;
}
case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
output_surface_state_ = OUTPUT_SURFACE_CREATING;
DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
DCHECK(!has_pending_tree_);
DCHECK(!active_tree_needs_first_draw_);
return;
case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD;
main_thread_needs_layer_textures_ = false;
return;
case ACTION_MANAGE_TILES:
UpdateStateOnManageTiles();
return;
}
}
void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
commit_count_++;
if (commit_was_aborted || settings_.main_frame_before_activation_enabled) {
commit_state_ = COMMIT_STATE_IDLE;
} else if (settings_.main_frame_before_draw_enabled) {
commit_state_ = settings_.impl_side_painting
? COMMIT_STATE_WAITING_FOR_ACTIVATION
: COMMIT_STATE_IDLE;
} else {
commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
}
has_pending_tree_ = settings_.impl_side_painting && !commit_was_aborted;
if (readback_state_ == READBACK_STATE_WAITING_FOR_COMMIT) {
readback_state_ = has_pending_tree_
? READBACK_STATE_WAITING_FOR_ACTIVATION
: READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
} else if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT) {
readback_state_ = has_pending_tree_
? READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION
: READBACK_STATE_IDLE;
} else {
DCHECK(readback_state_ == READBACK_STATE_IDLE);
}
if (readback_state_ == READBACK_STATE_IDLE ||
readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION) {
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) {
forced_redraw_state_ = has_pending_tree_
? FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION
: FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
}
DCHECK_NE(output_surface_state_,
OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION);
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) {
if (has_pending_tree_) {
output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION;
} else {
output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
needs_redraw_ = true;
}
}
}
if (!has_pending_tree_ &&
(!commit_was_aborted ||
readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK ||
forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) {
needs_redraw_ = true;
active_tree_needs_first_draw_ = true;
}
pending_tree_is_ready_for_activation_ = false;
if (draw_if_possible_failed_)
last_frame_number_swap_performed_ = -1;
if (has_pending_tree_ || needs_redraw_)
texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
else
texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
if (continuous_painting_)
needs_commit_ = true;
}
void SchedulerStateMachine::UpdateStateOnActivation() {
if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION)
commit_state_ = COMMIT_STATE_IDLE;
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION)
forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
if (readback_state_ == READBACK_STATE_WAITING_FOR_ACTIVATION) {
readback_state_ = READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
} else if (readback_state_ ==
READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION) {
if (needs_back_to_back_readback_) {
if (commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_SENT) {
readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT;
} else {
needs_commit_ = true;
readback_state_ = READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME;
}
needs_back_to_back_readback_ = false;
} else {
readback_state_ = READBACK_STATE_IDLE;
}
}
has_pending_tree_ = false;
pending_tree_is_ready_for_activation_ = false;
active_tree_needs_first_draw_ = true;
needs_redraw_ = true;
}
void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) {
DCHECK(readback_state_ != READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT &&
readback_state_ != READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
<< *AsValue();
if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK) {
DCHECK(!has_pending_tree_);
commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
readback_state_ = READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT;
} else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) {
forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
}
if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW)
commit_state_ = COMMIT_STATE_IDLE;
if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
needs_redraw_ = false;
draw_if_possible_failed_ = false;
active_tree_needs_first_draw_ = false;
if (did_swap)
last_frame_number_swap_performed_ = current_frame_number_;
}
void SchedulerStateMachine::UpdateStateOnManageTiles() {
needs_manage_tiles_ = false;
}
void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() {
DCHECK(!main_thread_needs_layer_textures_);
DCHECK_NE(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD);
main_thread_needs_layer_textures_ = true;
}
void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() {
skip_next_begin_main_frame_to_reduce_latency_ = true;
}
bool SchedulerStateMachine::BeginImplFrameNeeded() const {
if (!SupportsProactiveBeginImplFrame())
return BeginImplFrameNeededToDraw();
return BeginImplFrameNeededToDraw() ||
ProactiveBeginImplFrameWanted();
}
bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const {
if (!SupportsProactiveBeginImplFrame()) {
return !BeginImplFrameNeededToDraw() &&
ProactiveBeginImplFrameWanted();
}
return false;
}
bool SchedulerStateMachine::SupportsProactiveBeginImplFrame() const {
return !settings_.using_synchronous_renderer_compositor &&
settings_.throttle_frame_production;
}
bool SchedulerStateMachine::BeginImplFrameNeededToDraw() const {
if (!HasInitializedOutputSurface())
return false;
if (!can_draw_)
return false;
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
return true;
if (!visible_)
return false;
if (swap_used_incomplete_tile_)
return true;
return needs_redraw_;
}
bool SchedulerStateMachine::ProactiveBeginImplFrameWanted() const {
if (!HasInitializedOutputSurface())
return false;
if (!visible_)
return false;
if (needs_commit_ || commit_state_ != COMMIT_STATE_IDLE)
return true;
if (has_pending_tree_)
return true;
if (needs_manage_tiles_)
return true;
if (last_frame_number_swap_performed_ == current_frame_number_)
return true;
return false;
}
void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) {
AdvanceCurrentFrameNumber();
last_begin_impl_frame_args_ = args;
DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) << *AsValue();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
}
void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() {
DCHECK_EQ(begin_impl_frame_state_,
BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)
<< *AsValue();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME;
}
void SchedulerStateMachine::OnBeginImplFrameDeadline() {
DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
<< *AsValue();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
}
void SchedulerStateMachine::OnBeginImplFrameIdle() {
DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
<< *AsValue();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
}
bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
if (readback_state_ != READBACK_STATE_IDLE)
return false;
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
return false;
if (output_surface_state_ == OUTPUT_SURFACE_LOST)
return true;
if (active_tree_needs_first_draw_)
return true;
if (!needs_redraw_)
return false;
if (commit_state_ == COMMIT_STATE_IDLE && !has_pending_tree_)
return true;
if (smoothness_takes_priority_)
return true;
return false;
}
bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
if (CommitPending() && (active_tree_needs_first_draw_ || has_pending_tree_))
return true;
if (last_frame_number_begin_main_frame_sent_ == current_frame_number_ &&
(begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING ||
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME))
return false;
if (commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED ||
commit_state_ == COMMIT_STATE_READY_TO_COMMIT)
return true;
if (has_pending_tree_)
return true;
if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
return (active_tree_needs_first_draw_ ||
last_frame_number_swap_performed_ == current_frame_number_) &&
last_frame_number_begin_main_frame_sent_ != current_frame_number_;
}
return active_tree_needs_first_draw_;
}
void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() {
AdvanceCurrentFrameNumber();
inside_poll_for_anticipated_draw_triggers_ = true;
}
void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() {
inside_poll_for_anticipated_draw_triggers_ = false;
}
void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; }
void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
void SchedulerStateMachine::SetNeedsManageTiles() {
if (!needs_manage_tiles_) {
TRACE_EVENT0("cc",
"SchedulerStateMachine::SetNeedsManageTiles");
needs_manage_tiles_ = true;
}
}
void SchedulerStateMachine::SetSwapUsedIncompleteTile(
bool used_incomplete_tile) {
swap_used_incomplete_tile_ = used_incomplete_tile;
}
void SchedulerStateMachine::SetSmoothnessTakesPriority(
bool smoothness_takes_priority) {
smoothness_takes_priority_ = smoothness_takes_priority;
}
void SchedulerStateMachine::DidDrawIfPossibleCompleted(
DrawSwapReadbackResult::DrawResult result) {
switch (result) {
case DrawSwapReadbackResult::INVALID_RESULT:
NOTREACHED() << "Uninitialized DrawSwapReadbackResult.";
break;
case DrawSwapReadbackResult::DRAW_ABORTED_CANT_DRAW:
case DrawSwapReadbackResult::DRAW_ABORTED_CANT_READBACK:
case DrawSwapReadbackResult::DRAW_ABORTED_CONTEXT_LOST:
NOTREACHED() << "Invalid return value from DrawAndSwapIfPossible:"
<< result;
break;
case DrawSwapReadbackResult::DRAW_SUCCESS:
consecutive_checkerboard_animations_ = 0;
forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
break;
case DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS:
needs_redraw_ = true;
if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE)
return;
needs_commit_ = true;
consecutive_checkerboard_animations_++;
if (settings_.timeout_and_draw_when_animation_checkerboards &&
consecutive_checkerboard_animations_ >=
settings_.maximum_number_of_failed_draws_before_draw_is_forced_) {
consecutive_checkerboard_animations_ = 0;
forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
}
break;
case DrawSwapReadbackResult::DRAW_ABORTED_MISSING_HIGH_RES_CONTENT:
needs_commit_ = true;
break;
}
}
void SchedulerStateMachine::SetNeedsCommit() { needs_commit_ = true; }
void SchedulerStateMachine::SetNeedsForcedCommitForReadback() {
DCHECK(readback_state_ == READBACK_STATE_IDLE ||
readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT ||
readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION);
if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION) {
needs_back_to_back_readback_ = true;
} else if (commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_SENT) {
readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT;
} else {
needs_commit_ = true;
readback_state_ = READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME;
}
}
void SchedulerStateMachine::NotifyReadyToCommit() {
DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED) << *AsValue();
commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
}
void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
if (did_handle) {
bool commit_was_aborted = true;
UpdateStateOnCommit(commit_was_aborted);
} else {
DCHECK_NE(readback_state_, READBACK_STATE_WAITING_FOR_COMMIT);
commit_state_ = COMMIT_STATE_IDLE;
SetNeedsCommit();
}
}
void SchedulerStateMachine::DidManageTiles() {
needs_manage_tiles_ = false;
manage_tiles_funnel_++;
}
void SchedulerStateMachine::DidLoseOutputSurface() {
if (output_surface_state_ == OUTPUT_SURFACE_LOST ||
output_surface_state_ == OUTPUT_SURFACE_CREATING)
return;
output_surface_state_ = OUTPUT_SURFACE_LOST;
needs_redraw_ = false;
}
void SchedulerStateMachine::NotifyReadyToActivate() {
if (has_pending_tree_)
pending_tree_is_ready_for_activation_ = true;
}
void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_CREATING);
output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT;
if (did_create_and_initialize_first_output_surface_) {
needs_commit_ = true;
}
did_create_and_initialize_first_output_surface_ = true;
}
void SchedulerStateMachine::NotifyBeginMainFrameStarted() {
DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
DCHECK(readback_state_ == READBACK_STATE_IDLE ||
readback_state_ == READBACK_STATE_WAITING_FOR_COMMIT ||
readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT);
commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED;
}
bool SchedulerStateMachine::HasInitializedOutputSurface() const {
switch (output_surface_state_) {
case OUTPUT_SURFACE_LOST:
case OUTPUT_SURFACE_CREATING:
return false;
case OUTPUT_SURFACE_ACTIVE:
case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT:
case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION:
return true;
}
NOTREACHED();
return false;
}
}