cc: Add readback and forced draw states to the Scheduler.

Readback doesn't have all its steps synchronized properly with
impl side painting enabled. This patch prevents the readback
commit from being swapped to screen and avoids using non-readback
commits for readback by adding a SynchronousReadbackState.

This patch also gives forced draws due to checkerboarding its
own ForcedReadback state that behaves independently of readback.

Previously readback and forced draws shared drawing mechanisms,
but we want readbacks to occur ASAP while we want forced draws
to occur inline with the normal frame scheduling.

BUG=276082

Review URL: https://chromiumcodereview.appspot.com/23503003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221854 0039d316-1c4b-4281-b951-d872f2087c98
parent ad06cdec
...@@ -54,9 +54,9 @@ void Scheduler::SetNeedsCommit() { ...@@ -54,9 +54,9 @@ void Scheduler::SetNeedsCommit() {
ProcessScheduledActions(); ProcessScheduledActions();
} }
void Scheduler::SetNeedsForcedCommit() { void Scheduler::SetNeedsForcedCommitForReadback() {
state_machine_.SetNeedsCommit(); state_machine_.SetNeedsCommit();
state_machine_.SetNeedsForcedCommit(); state_machine_.SetNeedsForcedCommitForReadback();
ProcessScheduledActions(); ProcessScheduledActions();
} }
...@@ -70,11 +70,6 @@ void Scheduler::DidSwapUseIncompleteTile() { ...@@ -70,11 +70,6 @@ void Scheduler::DidSwapUseIncompleteTile() {
ProcessScheduledActions(); ProcessScheduledActions();
} }
void Scheduler::SetNeedsForcedRedraw() {
state_machine_.SetNeedsForcedRedraw();
ProcessScheduledActions();
}
void Scheduler::SetMainThreadNeedsLayerTextures() { void Scheduler::SetMainThreadNeedsLayerTextures() {
state_machine_.SetMainThreadNeedsLayerTextures(); state_machine_.SetMainThreadNeedsLayerTextures();
ProcessScheduledActions(); ProcessScheduledActions();
...@@ -178,7 +173,7 @@ void Scheduler::BeginFrame(const BeginFrameArgs& args) { ...@@ -178,7 +173,7 @@ void Scheduler::BeginFrame(const BeginFrameArgs& args) {
} }
void Scheduler::DrawAndSwapIfPossible() { void Scheduler::DrawAndSwapIfPossible() {
ScheduledActionDrawAndSwapResult result = DrawSwapReadbackResult result =
client_->ScheduledActionDrawAndSwapIfPossible(); client_->ScheduledActionDrawAndSwapIfPossible();
state_machine_.DidDrawIfPossibleCompleted(result.did_draw); state_machine_.DidDrawIfPossibleCompleted(result.did_draw);
if (result.did_swap) if (result.did_swap)
...@@ -186,12 +181,16 @@ void Scheduler::DrawAndSwapIfPossible() { ...@@ -186,12 +181,16 @@ void Scheduler::DrawAndSwapIfPossible() {
} }
void Scheduler::DrawAndSwapForced() { void Scheduler::DrawAndSwapForced() {
ScheduledActionDrawAndSwapResult result = DrawSwapReadbackResult result = client_->ScheduledActionDrawAndSwapForced();
client_->ScheduledActionDrawAndSwapForced();
if (result.did_swap) if (result.did_swap)
has_pending_begin_frame_ = false; has_pending_begin_frame_ = false;
} }
void Scheduler::DrawAndReadback() {
DrawSwapReadbackResult result = client_->ScheduledActionDrawAndReadback();
DCHECK(!result.did_swap);
}
void Scheduler::ProcessScheduledActions() { void Scheduler::ProcessScheduledActions() {
// We do not allow ProcessScheduledActions to be recursive. // We do not allow ProcessScheduledActions to be recursive.
// The top-level call will iteratively execute the next action for us anyway. // The top-level call will iteratively execute the next action for us anyway.
...@@ -202,6 +201,7 @@ void Scheduler::ProcessScheduledActions() { ...@@ -202,6 +201,7 @@ void Scheduler::ProcessScheduledActions() {
SchedulerStateMachine::Action action; SchedulerStateMachine::Action action;
do { do {
state_machine_.CheckInvariants();
action = state_machine_.NextAction(); action = state_machine_.NextAction();
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
"SchedulerStateMachine", "SchedulerStateMachine",
...@@ -223,16 +223,19 @@ void Scheduler::ProcessScheduledActions() { ...@@ -223,16 +223,19 @@ void Scheduler::ProcessScheduledActions() {
case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE: case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE:
client_->ScheduledActionActivatePendingTree(); client_->ScheduledActionActivatePendingTree();
break; break;
case SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE: case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
DrawAndSwapIfPossible(); DrawAndSwapIfPossible();
break; break;
case SchedulerStateMachine::ACTION_DRAW_FORCED: case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
DrawAndSwapForced(); DrawAndSwapForced();
break; break;
case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
// No action is actually performed, but this allows the state machine to // No action is actually performed, but this allows the state machine to
// advance out of its waiting to draw state without actually drawing. // advance out of its waiting to draw state without actually drawing.
break; break;
case SchedulerStateMachine::ACTION_DRAW_AND_READBACK:
DrawAndReadback();
break;
case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
client_->ScheduledActionBeginOutputSurfaceCreation(); client_->ScheduledActionBeginOutputSurfaceCreation();
break; break;
......
...@@ -20,25 +20,23 @@ namespace cc { ...@@ -20,25 +20,23 @@ namespace cc {
class Thread; class Thread;
struct ScheduledActionDrawAndSwapResult { struct DrawSwapReadbackResult {
ScheduledActionDrawAndSwapResult() DrawSwapReadbackResult()
: did_draw(false), : did_draw(false), did_swap(false), did_readback(false) {}
did_swap(false) {} DrawSwapReadbackResult(bool did_draw, bool did_swap, bool did_readback)
ScheduledActionDrawAndSwapResult(bool did_draw, bool did_swap) : did_draw(did_draw), did_swap(did_swap), did_readback(did_readback) {}
: did_draw(did_draw),
did_swap(did_swap) {}
bool did_draw; bool did_draw;
bool did_swap; bool did_swap;
bool did_readback;
}; };
class SchedulerClient { class SchedulerClient {
public: public:
virtual void SetNeedsBeginFrameOnImplThread(bool enable) = 0; virtual void SetNeedsBeginFrameOnImplThread(bool enable) = 0;
virtual void ScheduledActionSendBeginFrameToMainThread() = 0; virtual void ScheduledActionSendBeginFrameToMainThread() = 0;
virtual ScheduledActionDrawAndSwapResult virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() = 0;
ScheduledActionDrawAndSwapIfPossible() = 0; virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() = 0;
virtual ScheduledActionDrawAndSwapResult virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() = 0;
ScheduledActionDrawAndSwapForced() = 0;
virtual void ScheduledActionCommit() = 0; virtual void ScheduledActionCommit() = 0;
virtual void ScheduledActionUpdateVisibleTiles() = 0; virtual void ScheduledActionUpdateVisibleTiles() = 0;
virtual void ScheduledActionActivatePendingTree() = 0; virtual void ScheduledActionActivatePendingTree() = 0;
...@@ -72,17 +70,13 @@ class CC_EXPORT Scheduler { ...@@ -72,17 +70,13 @@ class CC_EXPORT Scheduler {
void SetNeedsCommit(); void SetNeedsCommit();
// Like SetNeedsCommit(), but ensures a commit will definitely happen even if // Like SetNeedsCommit(), but ensures a commit will definitely happen even if
// we are not visible. // we are not visible. Will eventually result in a forced draw internally.
void SetNeedsForcedCommit(); void SetNeedsForcedCommitForReadback();
void SetNeedsRedraw(); void SetNeedsRedraw();
void SetMainThreadNeedsLayerTextures(); void SetMainThreadNeedsLayerTextures();
// Like SetNeedsRedraw(), but ensures the draw will definitely happen even if
// we are not visible.
void SetNeedsForcedRedraw();
void DidSwapUseIncompleteTile(); void DidSwapUseIncompleteTile();
void FinishCommit(); void FinishCommit();
...@@ -116,6 +110,7 @@ class CC_EXPORT Scheduler { ...@@ -116,6 +110,7 @@ class CC_EXPORT Scheduler {
void SetupNextBeginFrameIfNeeded(); void SetupNextBeginFrameIfNeeded();
void DrawAndSwapIfPossible(); void DrawAndSwapIfPossible();
void DrawAndSwapForced(); void DrawAndSwapForced();
void DrawAndReadback();
void ProcessScheduledActions(); void ProcessScheduledActions();
const SchedulerSettings settings_; const SchedulerSettings settings_;
......
...@@ -9,6 +9,7 @@ namespace cc { ...@@ -9,6 +9,7 @@ namespace cc {
SchedulerSettings::SchedulerSettings() SchedulerSettings::SchedulerSettings()
: impl_side_painting(false), : impl_side_painting(false),
timeout_and_draw_when_animation_checkerboards(true), timeout_and_draw_when_animation_checkerboards(true),
maximum_number_of_failed_draws_before_draw_is_forced_(3),
using_synchronous_renderer_compositor(false), using_synchronous_renderer_compositor(false),
throttle_frame_production(true) {} throttle_frame_production(true) {}
......
...@@ -16,6 +16,7 @@ class CC_EXPORT SchedulerSettings { ...@@ -16,6 +16,7 @@ class CC_EXPORT SchedulerSettings {
bool impl_side_painting; bool impl_side_painting;
bool timeout_and_draw_when_animation_checkerboards; bool timeout_and_draw_when_animation_checkerboards;
int maximum_number_of_failed_draws_before_draw_is_forced_;
bool using_synchronous_renderer_compositor; bool using_synchronous_renderer_compositor;
bool throttle_frame_production; bool throttle_frame_production;
}; };
......
This diff is collapsed.
...@@ -50,7 +50,6 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -50,7 +50,6 @@ class CC_EXPORT SchedulerStateMachine {
COMMIT_STATE_FRAME_IN_PROGRESS, COMMIT_STATE_FRAME_IN_PROGRESS,
COMMIT_STATE_READY_TO_COMMIT, COMMIT_STATE_READY_TO_COMMIT,
COMMIT_STATE_WAITING_FOR_FIRST_DRAW, COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW,
}; };
static const char* CommitStateToString(CommitState state); static const char* CommitStateToString(CommitState state);
...@@ -61,6 +60,27 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -61,6 +60,27 @@ class CC_EXPORT SchedulerStateMachine {
}; };
static const char* TextureStateToString(TextureState state); static const char* TextureStateToString(TextureState state);
enum SynchronousReadbackState {
READBACK_STATE_IDLE,
READBACK_STATE_NEEDS_BEGIN_FRAME,
READBACK_STATE_WAITING_FOR_COMMIT,
READBACK_STATE_WAITING_FOR_ACTIVATION,
READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK,
READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT,
READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION,
};
static const char* SynchronousReadbackStateToString(
SynchronousReadbackState state);
enum ForcedRedrawOnTimeoutState {
FORCED_REDRAW_STATE_IDLE,
FORCED_REDRAW_STATE_WAITING_FOR_COMMIT,
FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION,
FORCED_REDRAW_STATE_WAITING_FOR_DRAW,
};
static const char* ForcedRedrawOnTimeoutStateToString(
ForcedRedrawOnTimeoutState state);
bool CommitPending() const { bool CommitPending() const {
return commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS || return commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS ||
commit_state_ == COMMIT_STATE_READY_TO_COMMIT; commit_state_ == COMMIT_STATE_READY_TO_COMMIT;
...@@ -74,9 +94,10 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -74,9 +94,10 @@ class CC_EXPORT SchedulerStateMachine {
ACTION_COMMIT, ACTION_COMMIT,
ACTION_UPDATE_VISIBLE_TILES, ACTION_UPDATE_VISIBLE_TILES,
ACTION_ACTIVATE_PENDING_TREE, ACTION_ACTIVATE_PENDING_TREE,
ACTION_DRAW_IF_POSSIBLE, ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
ACTION_DRAW_FORCED, ACTION_DRAW_AND_SWAP_FORCED,
ACTION_DRAW_AND_SWAP_ABORT, ACTION_DRAW_AND_SWAP_ABORT,
ACTION_DRAW_AND_READBACK,
ACTION_BEGIN_OUTPUT_SURFACE_CREATION, ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD, ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD,
}; };
...@@ -86,6 +107,7 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -86,6 +107,7 @@ class CC_EXPORT SchedulerStateMachine {
Action NextAction() const; Action NextAction() const;
void UpdateState(Action action); void UpdateState(Action action);
void CheckInvariants();
// Indicates whether the main thread needs a begin frame callback in order to // Indicates whether the main thread needs a begin frame callback in order to
// make progress. // make progress.
...@@ -106,15 +128,12 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -106,15 +128,12 @@ class CC_EXPORT SchedulerStateMachine {
// or the screen being damaged and simply needing redisplay. // or the screen being damaged and simply needing redisplay.
void SetNeedsRedraw(); void SetNeedsRedraw();
// As SetNeedsRedraw(), but ensures the draw will definitely happen even if
// we are not visible.
void SetNeedsForcedRedraw();
// Indicates that a redraw is required because we are currently rendering // Indicates that a redraw is required because we are currently rendering
// with a low resolution or checkerboarded tile. // with a low resolution or checkerboarded tile.
void DidSwapUseIncompleteTile(); void DidSwapUseIncompleteTile();
// Indicates whether ACTION_DRAW_IF_POSSIBLE drew to the screen or not. // Indicates whether ACTION_DRAW_AND_SWAP_IF_POSSIBLE drew to the screen or
// not.
void DidDrawIfPossibleCompleted(bool success); void DidDrawIfPossibleCompleted(bool success);
// Indicates that a new commit flow needs to be performed, either to pull // Indicates that a new commit flow needs to be performed, either to pull
...@@ -126,7 +145,7 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -126,7 +145,7 @@ class CC_EXPORT SchedulerStateMachine {
// thread even if we are not visible. After this call we expect to go through // thread even if we are not visible. After this call we expect to go through
// the forced commit flow and then return to waiting for a non-forced // the forced commit flow and then return to waiting for a non-forced
// begin frame to finish. // begin frame to finish.
void SetNeedsForcedCommit(); void SetNeedsForcedCommitForReadback();
// Call this only in response to receiving an // Call this only in response to receiving an
// ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD from NextAction. // ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD from NextAction.
...@@ -141,7 +160,8 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -141,7 +160,8 @@ class CC_EXPORT SchedulerStateMachine {
// Request exclusive access to the textures that back single buffered // Request exclusive access to the textures that back single buffered
// layers on behalf of the main thread. Upon acquisition, // layers on behalf of the main thread. Upon acquisition,
// ACTION_DRAW_IF_POSSIBLE will not draw until the main thread releases the // ACTION_DRAW_AND_SWAP_IF_POSSIBLE will not draw until the main thread
// releases the
// textures to the impl thread by committing the layers. // textures to the impl thread by committing the layers.
void SetMainThreadNeedsLayerTextures(); void SetMainThreadNeedsLayerTextures();
...@@ -162,9 +182,6 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -162,9 +182,6 @@ class CC_EXPORT SchedulerStateMachine {
void DidCreateAndInitializeOutputSurface(); void DidCreateAndInitializeOutputSurface();
bool HasInitializedOutputSurface() const; bool HasInitializedOutputSurface() const;
// Exposed for testing purposes.
void SetMaximumNumberOfFailedDrawsBeforeDrawIsForced(int num_draws);
// True if we need to abort draws to make forward progress. // True if we need to abort draws to make forward progress.
bool PendingDrawsShouldBeAborted() const; bool PendingDrawsShouldBeAborted() const;
...@@ -181,7 +198,7 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -181,7 +198,7 @@ class CC_EXPORT SchedulerStateMachine {
bool ShouldSendBeginFrameToMainThread() const; bool ShouldSendBeginFrameToMainThread() const;
bool ShouldCommit() const; bool ShouldCommit() const;
bool HasDrawnThisFrame() const; bool HasDrawnAndSwappedThisFrame() const;
bool HasActivatedPendingTreeThisFrame() const; bool HasActivatedPendingTreeThisFrame() const;
bool HasUpdatedVisibleTilesThisFrame() const; bool HasUpdatedVisibleTilesThisFrame() const;
bool HasSentBeginFrameToMainThreadThisFrame() const; bool HasSentBeginFrameToMainThreadThisFrame() const;
...@@ -194,21 +211,19 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -194,21 +211,19 @@ class CC_EXPORT SchedulerStateMachine {
OutputSurfaceState output_surface_state_; OutputSurfaceState output_surface_state_;
CommitState commit_state_; CommitState commit_state_;
TextureState texture_state_;
ForcedRedrawOnTimeoutState forced_redraw_state_;
SynchronousReadbackState readback_state_;
int commit_count_; int commit_count_;
int current_frame_number_; int current_frame_number_;
int last_frame_number_where_begin_frame_sent_to_main_thread_; int last_frame_number_where_begin_frame_sent_to_main_thread_;
int last_frame_number_where_draw_was_called_; int last_frame_number_swap_performed_;
int last_frame_number_where_update_visible_tiles_was_called_; int last_frame_number_where_update_visible_tiles_was_called_;
int consecutive_failed_draws_; int consecutive_failed_draws_;
int maximum_number_of_failed_draws_before_draw_is_forced_;
bool needs_redraw_; bool needs_redraw_;
bool swap_used_incomplete_tile_; bool swap_used_incomplete_tile_;
bool needs_forced_redraw_;
bool needs_forced_redraw_after_next_commit_;
bool needs_commit_; bool needs_commit_;
bool needs_forced_commit_;
bool expect_immediate_begin_frame_for_main_thread_;
bool main_thread_needs_layer_textures_; bool main_thread_needs_layer_textures_;
bool inside_begin_frame_; bool inside_begin_frame_;
BeginFrameArgs last_begin_frame_args_; BeginFrameArgs last_begin_frame_args_;
...@@ -217,9 +232,8 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -217,9 +232,8 @@ class CC_EXPORT SchedulerStateMachine {
bool can_draw_; bool can_draw_;
bool has_pending_tree_; bool has_pending_tree_;
bool pending_tree_is_ready_for_activation_; bool pending_tree_is_ready_for_activation_;
bool active_tree_has_been_drawn_; bool active_tree_needs_first_draw_;
bool draw_if_possible_failed_; bool draw_if_possible_failed_;
TextureState texture_state_;
bool did_create_and_initialize_first_output_surface_; bool did_create_and_initialize_first_output_surface_;
private: private:
......
...@@ -90,21 +90,32 @@ class FakeSchedulerClient : public SchedulerClient { ...@@ -90,21 +90,32 @@ class FakeSchedulerClient : public SchedulerClient {
actions_.push_back("ScheduledActionSendBeginFrameToMainThread"); actions_.push_back("ScheduledActionSendBeginFrameToMainThread");
states_.push_back(scheduler_->StateAsValue().release()); states_.push_back(scheduler_->StateAsValue().release());
} }
virtual ScheduledActionDrawAndSwapResult virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
ScheduledActionDrawAndSwapIfPossible() OVERRIDE { OVERRIDE {
actions_.push_back("ScheduledActionDrawAndSwapIfPossible"); actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
states_.push_back(scheduler_->StateAsValue().release()); states_.push_back(scheduler_->StateAsValue().release());
num_draws_++; num_draws_++;
return ScheduledActionDrawAndSwapResult(draw_will_happen_, bool did_readback = false;
draw_will_happen_ && return DrawSwapReadbackResult(
swap_will_happen_if_draw_happens_); draw_will_happen_,
draw_will_happen_ && swap_will_happen_if_draw_happens_,
did_readback);
} }
virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced() virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
OVERRIDE {
actions_.push_back("ScheduledActionDrawAndSwapForced"); actions_.push_back("ScheduledActionDrawAndSwapForced");
states_.push_back(scheduler_->StateAsValue().release()); states_.push_back(scheduler_->StateAsValue().release());
return ScheduledActionDrawAndSwapResult(true, bool did_draw = true;
swap_will_happen_if_draw_happens_); bool did_swap = swap_will_happen_if_draw_happens_;
bool did_readback = false;
return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
}
virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE {
actions_.push_back("ScheduledActionDrawAndReadback");
states_.push_back(scheduler_->StateAsValue().release());
bool did_draw = true;
bool did_swap = false;
bool did_readback = true;
return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
} }
virtual void ScheduledActionCommit() OVERRIDE { virtual void ScheduledActionCommit() OVERRIDE {
actions_.push_back("ScheduledActionCommit"); actions_.push_back("ScheduledActionCommit");
...@@ -399,18 +410,20 @@ TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) { ...@@ -399,18 +410,20 @@ TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) {
class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient { class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
public: public:
virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {} virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {}
virtual ScheduledActionDrawAndSwapResult virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
ScheduledActionDrawAndSwapIfPossible() OVERRIDE { OVERRIDE {
// Only SetNeedsRedraw the first time this is called // Only SetNeedsRedraw the first time this is called
if (!num_draws_) if (!num_draws_)
scheduler_->SetNeedsRedraw(); scheduler_->SetNeedsRedraw();
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
} }
virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced() virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
OVERRIDE {
NOTREACHED(); NOTREACHED();
return ScheduledActionDrawAndSwapResult(true, true); bool did_draw = true;
bool did_swap = true;
bool did_readback = false;
return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
} }
virtual void ScheduledActionCommit() OVERRIDE {} virtual void ScheduledActionCommit() OVERRIDE {}
...@@ -498,8 +511,8 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient { ...@@ -498,8 +511,8 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
: set_needs_commit_on_next_draw_(false) {} : set_needs_commit_on_next_draw_(false) {}
virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {} virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {}
virtual ScheduledActionDrawAndSwapResult virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
ScheduledActionDrawAndSwapIfPossible() OVERRIDE { OVERRIDE {
// Only SetNeedsCommit the first time this is called // Only SetNeedsCommit the first time this is called
if (set_needs_commit_on_next_draw_) { if (set_needs_commit_on_next_draw_) {
scheduler_->SetNeedsCommit(); scheduler_->SetNeedsCommit();
...@@ -508,10 +521,12 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient { ...@@ -508,10 +521,12 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
} }
virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced() virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
OVERRIDE {
NOTREACHED(); NOTREACHED();
return ScheduledActionDrawAndSwapResult(true, true); bool did_draw = true;
bool did_swap = false;
bool did_readback = false;
return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
} }
virtual void ScheduledActionCommit() OVERRIDE {} virtual void ScheduledActionCommit() OVERRIDE {}
...@@ -639,11 +654,37 @@ TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) { ...@@ -639,11 +654,37 @@ TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) {
client.SetDrawWillHappen(true); client.SetDrawWillHappen(true);
client.SetSwapWillHappenIfDrawHappens(false); client.SetSwapWillHappenIfDrawHappens(false);
// Get the compositor to do a ScheduledActionDrawAndSwapForced. // Get the compositor to do a ScheduledActionDrawAndReadback.
scheduler->SetCanDraw(true);
scheduler->SetNeedsRedraw();
scheduler->SetNeedsForcedCommitForReadback();
scheduler->FinishCommit();
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
}
TEST(SchedulerTest, BackToBackReadbackAllowed) {
// Some clients call readbacks twice in a row before the replacement
// commit comes in. Make sure it is allowed.
FakeSchedulerClient client;
SchedulerSettings default_scheduler_settings;
Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
// Get the compositor to do 2 ScheduledActionDrawAndReadbacks before
// the replacement commit comes in.
scheduler->SetCanDraw(true); scheduler->SetCanDraw(true);
scheduler->SetNeedsRedraw(); scheduler->SetNeedsRedraw();
scheduler->SetNeedsForcedRedraw(); scheduler->SetNeedsForcedCommitForReadback();
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapForced")); scheduler->FinishCommit();
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
client.Reset();
scheduler->SetNeedsForcedCommitForReadback();
scheduler->FinishCommit();
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
// The replacement commit comes in after 2 readbacks.
client.Reset();
scheduler->FinishCommit();
} }
} // namespace } // namespace
......
...@@ -375,6 +375,12 @@ void LayerTreeTest::PostSetNeedsCommitToMainThread() { ...@@ -375,6 +375,12 @@ void LayerTreeTest::PostSetNeedsCommitToMainThread() {
main_thread_weak_ptr_)); main_thread_weak_ptr_));
} }
void LayerTreeTest::PostReadbackToMainThread() {
proxy()->MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&LayerTreeTest::DispatchReadback, main_thread_weak_ptr_));
}
void LayerTreeTest::PostAcquireLayerTextures() { void LayerTreeTest::PostAcquireLayerTextures() {
proxy()->MainThreadTaskRunner()->PostTask( proxy()->MainThreadTaskRunner()->PostTask(
FROM_HERE, FROM_HERE,
...@@ -504,6 +510,15 @@ void LayerTreeTest::DispatchSetNeedsCommit() { ...@@ -504,6 +510,15 @@ void LayerTreeTest::DispatchSetNeedsCommit() {
layer_tree_host_->SetNeedsCommit(); layer_tree_host_->SetNeedsCommit();
} }
void LayerTreeTest::DispatchReadback() {
DCHECK(!proxy() || proxy()->IsMainThread());
if (layer_tree_host_) {
char pixels[4];
layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
}
}
void LayerTreeTest::DispatchAcquireLayerTextures() { void LayerTreeTest::DispatchAcquireLayerTextures() {
DCHECK(!proxy() || proxy()->IsMainThread()); DCHECK(!proxy() || proxy()->IsMainThread());
......
...@@ -112,6 +112,7 @@ class LayerTreeTest : public testing::Test, public TestHooks { ...@@ -112,6 +112,7 @@ class LayerTreeTest : public testing::Test, public TestHooks {
void PostAddAnimationToMainThread(Layer* layer_to_receive_animation); void PostAddAnimationToMainThread(Layer* layer_to_receive_animation);
void PostAddInstantAnimationToMainThread(Layer* layer_to_receive_animation); void PostAddInstantAnimationToMainThread(Layer* layer_to_receive_animation);
void PostSetNeedsCommitToMainThread(); void PostSetNeedsCommitToMainThread();
void PostReadbackToMainThread();
void PostAcquireLayerTextures(); void PostAcquireLayerTextures();
void PostSetNeedsRedrawToMainThread(); void PostSetNeedsRedrawToMainThread();
void PostSetNeedsRedrawRectToMainThread(gfx::Rect damage_rect); void PostSetNeedsRedrawRectToMainThread(gfx::Rect damage_rect);
...@@ -132,6 +133,7 @@ class LayerTreeTest : public testing::Test, public TestHooks { ...@@ -132,6 +133,7 @@ class LayerTreeTest : public testing::Test, public TestHooks {
virtual void DispatchAddInstantAnimation(Layer* layer_to_receive_animation); virtual void DispatchAddInstantAnimation(Layer* layer_to_receive_animation);
virtual void DispatchAddAnimation(Layer* layer_to_receive_animation); virtual void DispatchAddAnimation(Layer* layer_to_receive_animation);
void DispatchSetNeedsCommit(); void DispatchSetNeedsCommit();
void DispatchReadback();
void DispatchAcquireLayerTextures(); void DispatchAcquireLayerTextures();
void DispatchSetNeedsRedraw(); void DispatchSetNeedsRedraw();
void DispatchSetNeedsRedrawRect(gfx::Rect damage_rect); void DispatchSetNeedsRedrawRect(gfx::Rect damage_rect);
......
...@@ -503,6 +503,104 @@ class LayerTreeHostTestCompositeAndReadbackBeforePreviousCommitDraws ...@@ -503,6 +503,104 @@ class LayerTreeHostTestCompositeAndReadbackBeforePreviousCommitDraws
MULTI_THREAD_TEST_F( MULTI_THREAD_TEST_F(
LayerTreeHostTestCompositeAndReadbackBeforePreviousCommitDraws); LayerTreeHostTestCompositeAndReadbackBeforePreviousCommitDraws);
class LayerTreeHostTestCompositeAndReadbackDuringForcedDraw
: public LayerTreeHostTest {
protected:
virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
// This enables forced draws after a single prepare to draw failure.
settings->timeout_and_draw_when_animation_checkerboards = true;
settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
}
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
LayerTreeHostImpl::FrameData* frame_data,
bool result) OVERRIDE {
EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
EXPECT_LE(host_impl->active_tree()->source_frame_number(), 2);
// Before we react to the failed draw by initiating the forced draw
// sequence, start a readback on the main thread.
if (host_impl->active_tree()->source_frame_number() == 0)
PostReadbackToMainThread();
// Returning false will eventually result in a forced draw.
return false;
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
// We should only draw for the readback and the forced draw.
EXPECT_GE(host_impl->active_tree()->source_frame_number(), 1);
EXPECT_LE(host_impl->active_tree()->source_frame_number(), 2);
}
virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
bool result) OVERRIDE {
// We should only swap for the forced draw.
EXPECT_EQ(host_impl->active_tree()->source_frame_number(), 2);
EndTest();
}
virtual void AfterTest() OVERRIDE {}
};
MULTI_THREAD_TEST_F(LayerTreeHostTestCompositeAndReadbackDuringForcedDraw);
class LayerTreeHostTestCompositeAndReadbackAfterForcedDraw
: public LayerTreeHostTest {
protected:
virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
// This enables forced draws after a single prepare to draw failure.
settings->timeout_and_draw_when_animation_checkerboards = true;
settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
}
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
LayerTreeHostImpl::FrameData* frame_data,
bool result) OVERRIDE {
EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
EXPECT_LE(host_impl->active_tree()->source_frame_number(), 3);
// Returning false will eventually result in a forced draw.
return false;
}
virtual void DidCommit() OVERRIDE {
if (layer_tree_host()->source_frame_number() == 1) {
// Avoid aborting the forced draw commit so source_frame_number
// increments.
layer_tree_host()->SetNeedsCommit();
} else if (layer_tree_host()->source_frame_number() == 2) {
// Perform a readback immediately after the forced draw's commit.
char pixels[4];
layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
}
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
// We should only draw for the the forced draw, readback, and
// replacement commit.
EXPECT_GE(host_impl->active_tree()->source_frame_number(), 1);
EXPECT_LE(host_impl->active_tree()->source_frame_number(), 3);
}
virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
bool result) OVERRIDE {
// We should only swap for the forced draw and replacement commit.
EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == 1 ||
host_impl->active_tree()->source_frame_number() == 3);
if (host_impl->active_tree()->source_frame_number() == 3)
EndTest();
}
virtual void AfterTest() OVERRIDE {}
};
MULTI_THREAD_TEST_F(LayerTreeHostTestCompositeAndReadbackAfterForcedDraw);
// If the layerTreeHost says it can't draw, Then we should not try to draw. // If the layerTreeHost says it can't draw, Then we should not try to draw.
class LayerTreeHostTestCanDrawBlocksDrawing : public LayerTreeHostTest { class LayerTreeHostTestCanDrawBlocksDrawing : public LayerTreeHostTest {
public: public:
......
...@@ -1461,6 +1461,29 @@ class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit ...@@ -1461,6 +1461,29 @@ class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit
EXPECT_EQ(1, times_output_surface_created_); EXPECT_EQ(1, times_output_surface_created_);
} }
virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
LayerTreeHostImpl::FrameData* frame_data,
bool result) OVERRIDE {
EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1);
return true;
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
// We should only draw for the readback and the replacement commit.
// The replacement commit will also be the first commit after output
// surface initialization.
EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1);
}
virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
bool result) OVERRIDE {
// We should only swap for the replacement commit.
EXPECT_EQ(host_impl->active_tree()->source_frame_number(), 1);
EndTest();
}
private: private:
int times_output_surface_created_; int times_output_surface_created_;
}; };
...@@ -1468,6 +1491,164 @@ class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit ...@@ -1468,6 +1491,164 @@ class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit
SINGLE_AND_MULTI_THREAD_TEST_F( SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit); LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit);
// This test verifies that losing an output surface right during a
// simultaneous readback and forced redraw works and does not deadlock.
class LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw
: public LayerTreeHostContextTest {
protected:
static const int kCommitAfterFirstOutputSurfaceInitSourceFrameNumber = 0;
static const int kReadbackCommitSourceFrameNumber = 1;
static const int kReadbackReplacementCommitSourceFrameNumber = 2;
static const int kCommitAfterSecondOutputSurfaceInitSourceFrameNumber = 3;
virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
// This enables forced draws after a single prepare to draw failure.
settings->timeout_and_draw_when_animation_checkerboards = true;
settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
}
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
LayerTreeHostImpl::FrameData* frame_data,
bool result) OVERRIDE {
EXPECT_TRUE(host_impl->active_tree()->source_frame_number() ==
kCommitAfterFirstOutputSurfaceInitSourceFrameNumber ||
host_impl->active_tree()->source_frame_number() ==
kCommitAfterSecondOutputSurfaceInitSourceFrameNumber ||
host_impl->active_tree()->source_frame_number() ==
kReadbackCommitSourceFrameNumber);
// Before we react to the failed draw by initiating the forced draw
// sequence, start a readback on the main thread and then lose the context
// to start output surface initialization all at the same time.
if (host_impl->active_tree()->source_frame_number() ==
kCommitAfterFirstOutputSurfaceInitSourceFrameNumber) {
PostReadbackToMainThread();
LoseContext();
}
// Returning false will eventually result in a forced draw.
return false;
}
virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
bool success) OVERRIDE {
// -1 is for the first output surface initialization.
EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == -1 ||
host_impl->active_tree()->source_frame_number() ==
kReadbackReplacementCommitSourceFrameNumber);
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
// We should only draw the first commit after output surface initialization
// and attempt to draw the readback commit (which will fail).
// All others should abort because the output surface is lost.
EXPECT_TRUE(host_impl->active_tree()->source_frame_number() ==
kCommitAfterSecondOutputSurfaceInitSourceFrameNumber ||
host_impl->active_tree()->source_frame_number() ==
kReadbackCommitSourceFrameNumber);
}
virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
bool result) OVERRIDE {
// We should only swap the first commit after the second output surface
// initialization.
EXPECT_TRUE(host_impl->active_tree()->source_frame_number() ==
kCommitAfterSecondOutputSurfaceInitSourceFrameNumber);
EndTest();
}
virtual void AfterTest() OVERRIDE {}
};
MULTI_THREAD_TEST_F(
LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw);
// This test verifies that losing an output surface right before a
// simultaneous readback and forced redraw works and does not deadlock.
class LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit
: public LayerTreeHostContextTest {
protected:
static const int kCommitAfterFirstOutputSurfaceInitSourceFrameNumber = 0;
static const int kReadbackCommitSourceFrameNumber = 1;
static const int kReadbackReplacementCommitSourceFrameNumber = 2;
static const int kForcedDrawCommitSourceFrameNumber = 2;
static const int kCommitAfterSecondOutputSurfaceInitSourceFrameNumber = 2;
virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
// This enables forced draws after a single prepare to draw failure.
settings->timeout_and_draw_when_animation_checkerboards = true;
settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
}
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
LayerTreeHostImpl::FrameData* frame_data,
bool result) OVERRIDE {
EXPECT_TRUE(host_impl->active_tree()->source_frame_number() ==
kCommitAfterFirstOutputSurfaceInitSourceFrameNumber ||
host_impl->active_tree()->source_frame_number() ==
kCommitAfterSecondOutputSurfaceInitSourceFrameNumber ||
host_impl->active_tree()->source_frame_number() ==
kReadbackCommitSourceFrameNumber);
// Before we react to the failed draw by initiating the forced draw
// sequence, start a readback on the main thread and then lose the context
// to start output surface initialization all at the same time.
if (host_impl->active_tree()->source_frame_number() ==
kCommitAfterFirstOutputSurfaceInitSourceFrameNumber) {
LoseContext();
}
// Returning false will eventually result in a forced draw.
return false;
}
virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
EXPECT_TRUE(succeeded);
if (layer_tree_host()->source_frame_number() > 0) {
// Perform a readback right after the second output surface
// initialization.
char pixels[4];
layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
}
}
virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
bool success) OVERRIDE {
// -1 is for the first output surface initialization.
EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == -1 ||
host_impl->active_tree()->source_frame_number() ==
kCommitAfterFirstOutputSurfaceInitSourceFrameNumber);
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
// We should only draw the first commit after output surface initialization
// and attempt to draw the readback commit (which will fail).
// All others should abort because the output surface is lost.
EXPECT_TRUE(host_impl->active_tree()->source_frame_number() ==
kForcedDrawCommitSourceFrameNumber ||
host_impl->active_tree()->source_frame_number() ==
kReadbackCommitSourceFrameNumber);
}
virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
bool result) OVERRIDE {
// We should only swap the first commit after the second output surface
// initialization.
EXPECT_TRUE(host_impl->active_tree()->source_frame_number() ==
kForcedDrawCommitSourceFrameNumber);
EndTest();
}
virtual void AfterTest() OVERRIDE {}
};
MULTI_THREAD_TEST_F(
LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit);
class ImplSidePaintingLayerTreeHostContextTest class ImplSidePaintingLayerTreeHostContextTest
: public LayerTreeHostContextTest { : public LayerTreeHostContextTest {
public: public:
......
...@@ -35,6 +35,7 @@ LayerTreeSettings::LayerTreeSettings() ...@@ -35,6 +35,7 @@ LayerTreeSettings::LayerTreeSettings()
calculate_top_controls_position(false), calculate_top_controls_position(false),
use_memory_management(true), use_memory_management(true),
timeout_and_draw_when_animation_checkerboards(true), timeout_and_draw_when_animation_checkerboards(true),
maximum_number_of_failed_draws_before_draw_is_forced_(3),
layer_transforms_should_scale_layer_contents(false), layer_transforms_should_scale_layer_contents(false),
minimum_contents_scale(0.0625f), minimum_contents_scale(0.0625f),
low_res_contents_scale_factor(0.125f), low_res_contents_scale_factor(0.125f),
......
...@@ -47,6 +47,7 @@ class CC_EXPORT LayerTreeSettings { ...@@ -47,6 +47,7 @@ class CC_EXPORT LayerTreeSettings {
bool calculate_top_controls_position; bool calculate_top_controls_position;
bool use_memory_management; bool use_memory_management;
bool timeout_and_draw_when_animation_checkerboards; bool timeout_and_draw_when_animation_checkerboards;
int maximum_number_of_failed_draws_before_draw_is_forced_;
bool layer_transforms_should_scale_layer_contents; bool layer_transforms_should_scale_layer_contents;
float minimum_contents_scale; float minimum_contents_scale;
float low_res_contents_scale_factor; float low_res_contents_scale_factor;
......
...@@ -70,10 +70,7 @@ bool SingleThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) { ...@@ -70,10 +70,7 @@ bool SingleThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) {
if (layer_tree_host_impl_->IsContextLost()) if (layer_tree_host_impl_->IsContextLost())
return false; return false;
layer_tree_host_impl_->SwapBuffers(frame);
} }
DidSwapFrame();
return true; return true;
} }
......
...@@ -126,19 +126,27 @@ bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) { ...@@ -126,19 +126,27 @@ bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) {
return false; return false;
} }
// Perform a synchronous commit. // Perform a synchronous commit with an associated readback.
ReadbackRequest request;
request.rect = rect;
request.pixels = pixels;
{ {
DebugScopedSetMainThreadBlocked main_thread_blocked(this); DebugScopedSetMainThreadBlocked main_thread_blocked(this);
CompletionEvent begin_frame_sent_to_main_thread_completion; CompletionEvent begin_frame_sent_to_main_thread_completion;
Proxy::ImplThreadTaskRunner()->PostTask( Proxy::ImplThreadTaskRunner()
FROM_HERE, ->PostTask(FROM_HERE,
base::Bind(&ThreadProxy::ForceCommitOnImplThread, base::Bind(&ThreadProxy::ForceCommitForReadbackOnImplThread,
impl_thread_weak_ptr_, impl_thread_weak_ptr_,
&begin_frame_sent_to_main_thread_completion)); &begin_frame_sent_to_main_thread_completion,
&request));
begin_frame_sent_to_main_thread_completion.Wait(); begin_frame_sent_to_main_thread_completion.Wait();
} }
in_composite_and_readback_ = true; in_composite_and_readback_ = true;
// This is the forced commit.
// Note: The Impl thread also queues a separate BeginFrameOnMainThread on the
// main thread, which will be called after this CompositeAndReadback
// completes, to replace the forced commit.
BeginFrameOnMainThread(scoped_ptr<BeginFrameAndCommitState>()); BeginFrameOnMainThread(scoped_ptr<BeginFrameAndCommitState>());
in_composite_and_readback_ = false; in_composite_and_readback_ = false;
...@@ -146,48 +154,35 @@ bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) { ...@@ -146,48 +154,35 @@ bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) {
// that it made. // that it made.
can_cancel_commit_ = false; can_cancel_commit_ = false;
// Perform a synchronous readback. request.completion.Wait();
ReadbackRequest request;
request.rect = rect;
request.pixels = pixels;
{
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::RequestReadbackOnImplThread,
impl_thread_weak_ptr_,
&request));
request.completion.Wait();
}
return request.success; return request.success;
} }
void ThreadProxy::ForceCommitOnImplThread(CompletionEvent* completion) { void ThreadProxy::ForceCommitForReadbackOnImplThread(
TRACE_EVENT0("cc", "ThreadProxy::ForceCommitOnImplThread"); CompletionEvent* begin_frame_sent_completion,
ReadbackRequest* request) {
TRACE_EVENT0("cc", "ThreadProxy::ForceCommitForReadbackOnImplThread");
DCHECK(IsImplThread()); DCHECK(IsImplThread());
DCHECK(!begin_frame_sent_to_main_thread_completion_event_on_impl_thread_); DCHECK(!begin_frame_sent_to_main_thread_completion_event_on_impl_thread_);
scheduler_on_impl_thread_->SetNeedsForcedCommit();
if (scheduler_on_impl_thread_->CommitPending()) {
completion->Signal();
return;
}
begin_frame_sent_to_main_thread_completion_event_on_impl_thread_ = completion;
}
void ThreadProxy::RequestReadbackOnImplThread(ReadbackRequest* request) {
DCHECK(Proxy::IsImplThread());
DCHECK(!readback_request_on_impl_thread_); DCHECK(!readback_request_on_impl_thread_);
if (!layer_tree_host_impl_) { if (!layer_tree_host_impl_) {
begin_frame_sent_completion->Signal();
request->success = false; request->success = false;
request->completion.Signal(); request->completion.Signal();
return; return;
} }
readback_request_on_impl_thread_ = request; readback_request_on_impl_thread_ = request;
scheduler_on_impl_thread_->SetNeedsRedraw();
scheduler_on_impl_thread_->SetNeedsForcedRedraw(); scheduler_on_impl_thread_->SetNeedsForcedCommitForReadback();
if (scheduler_on_impl_thread_->CommitPending()) {
begin_frame_sent_completion->Signal();
return;
}
begin_frame_sent_to_main_thread_completion_event_on_impl_thread_ =
begin_frame_sent_completion;
} }
void ThreadProxy::FinishAllRendering() { void ThreadProxy::FinishAllRendering() {
...@@ -999,14 +994,14 @@ void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() { ...@@ -999,14 +994,14 @@ void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
main_thread_weak_ptr_)); main_thread_weak_ptr_));
} }
ScheduledActionDrawAndSwapResult DrawSwapReadbackResult ThreadProxy::DrawSwapReadbackInternal(
ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) { bool forced_draw,
TRACE_EVENT1( bool swap_requested,
"cc", "ThreadProxy::ScheduledActionDrawAndSwap", "forced", forced_draw); bool readback_requested) {
DrawSwapReadbackResult result;
ScheduledActionDrawAndSwapResult result;
result.did_draw = false; result.did_draw = false;
result.did_swap = false; result.did_swap = false;
result.did_readback = false;
DCHECK(IsImplThread()); DCHECK(IsImplThread());
DCHECK(layer_tree_host_impl_.get()); DCHECK(layer_tree_host_impl_.get());
if (!layer_tree_host_impl_) if (!layer_tree_host_impl_)
...@@ -1041,7 +1036,10 @@ ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) { ...@@ -1041,7 +1036,10 @@ ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) {
// DrawLayers() depends on the result of PrepareToDraw(), it is guarded on // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
// CanDraw() as well. // CanDraw() as well.
bool drawing_for_readback = !!readback_request_on_impl_thread_; // readback_request_on_impl_thread_ may be for the pending tree, do
// not perform the readback unless explicitly requested.
bool drawing_for_readback =
readback_requested && !!readback_request_on_impl_thread_;
bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels(); bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels();
LayerTreeHostImpl::FrameData frame; LayerTreeHostImpl::FrameData frame;
...@@ -1074,17 +1072,19 @@ ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) { ...@@ -1074,17 +1072,19 @@ ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) {
layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
// Check for a pending CompositeAndReadback. // Check for a pending CompositeAndReadback.
if (readback_request_on_impl_thread_) { if (drawing_for_readback) {
readback_request_on_impl_thread_->success = false; DCHECK(!swap_requested);
if (draw_frame) { result.did_readback = false;
if (draw_frame && !layer_tree_host_impl_->IsContextLost()) {
layer_tree_host_impl_->Readback(readback_request_on_impl_thread_->pixels, layer_tree_host_impl_->Readback(readback_request_on_impl_thread_->pixels,
readback_request_on_impl_thread_->rect); readback_request_on_impl_thread_->rect);
readback_request_on_impl_thread_->success = result.did_readback = true;
!layer_tree_host_impl_->IsContextLost();
} }
readback_request_on_impl_thread_->success = result.did_readback;
readback_request_on_impl_thread_->completion.Signal(); readback_request_on_impl_thread_->completion.Signal();
readback_request_on_impl_thread_ = NULL; readback_request_on_impl_thread_ = NULL;
} else if (draw_frame) { } else if (draw_frame) {
DCHECK(swap_requested);
result.did_swap = layer_tree_host_impl_->SwapBuffers(frame); result.did_swap = layer_tree_host_impl_->SwapBuffers(frame);
if (frame.contains_incomplete_tile) if (frame.contains_incomplete_tile)
...@@ -1177,14 +1177,31 @@ void ThreadProxy::ScheduledActionAcquireLayerTexturesForMainThread() { ...@@ -1177,14 +1177,31 @@ void ThreadProxy::ScheduledActionAcquireLayerTexturesForMainThread() {
texture_acquisition_completion_event_on_impl_thread_ = NULL; texture_acquisition_completion_event_on_impl_thread_ = NULL;
} }
ScheduledActionDrawAndSwapResult DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
ThreadProxy::ScheduledActionDrawAndSwapIfPossible() { TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwap");
return ScheduledActionDrawAndSwapInternal(false); bool forced_draw = false;
bool swap_requested = true;
bool readback_requested = false;
return DrawSwapReadbackInternal(
forced_draw, swap_requested, readback_requested);
}
DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndSwapForced() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwapForced");
bool forced_draw = true;
bool swap_requested = true;
bool readback_requested = false;
return DrawSwapReadbackInternal(
forced_draw, swap_requested, readback_requested);
} }
ScheduledActionDrawAndSwapResult DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndReadback() {
ThreadProxy::ScheduledActionDrawAndSwapForced() { TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndReadback");
return ScheduledActionDrawAndSwapInternal(true); bool forced_draw = true;
bool swap_requested = false;
bool readback_requested = true;
return DrawSwapReadbackInternal(
forced_draw, swap_requested, readback_requested);
} }
void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) { void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) {
...@@ -1285,6 +1302,8 @@ void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { ...@@ -1285,6 +1302,8 @@ void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) {
scheduler_settings.impl_side_painting = settings.impl_side_painting; scheduler_settings.impl_side_painting = settings.impl_side_painting;
scheduler_settings.timeout_and_draw_when_animation_checkerboards = scheduler_settings.timeout_and_draw_when_animation_checkerboards =
settings.timeout_and_draw_when_animation_checkerboards; settings.timeout_and_draw_when_animation_checkerboards;
scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ =
settings.maximum_number_of_failed_draws_before_draw_is_forced_;
scheduler_settings.using_synchronous_renderer_compositor = scheduler_settings.using_synchronous_renderer_compositor =
settings.using_synchronous_renderer_compositor; settings.using_synchronous_renderer_compositor;
scheduler_settings.throttle_frame_production = scheduler_settings.throttle_frame_production =
......
...@@ -93,10 +93,10 @@ class ThreadProxy : public Proxy, ...@@ -93,10 +93,10 @@ class ThreadProxy : public Proxy,
// SchedulerClient implementation // SchedulerClient implementation
virtual void SetNeedsBeginFrameOnImplThread(bool enable) OVERRIDE; virtual void SetNeedsBeginFrameOnImplThread(bool enable) OVERRIDE;
virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE; virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE;
virtual ScheduledActionDrawAndSwapResult virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
ScheduledActionDrawAndSwapIfPossible() OVERRIDE;
virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced()
OVERRIDE; OVERRIDE;
virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE;
virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE;
virtual void ScheduledActionCommit() OVERRIDE; virtual void ScheduledActionCommit() OVERRIDE;
virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE; virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE;
virtual void ScheduledActionActivatePendingTree() OVERRIDE; virtual void ScheduledActionActivatePendingTree() OVERRIDE;
...@@ -142,7 +142,9 @@ class ThreadProxy : public Proxy, ...@@ -142,7 +142,9 @@ class ThreadProxy : public Proxy,
struct CommitPendingRequest; struct CommitPendingRequest;
struct SchedulerStateRequest; struct SchedulerStateRequest;
void ForceCommitOnImplThread(CompletionEvent* completion); void ForceCommitForReadbackOnImplThread(
CompletionEvent* begin_frame_sent_completion,
ReadbackRequest* request);
void StartCommitOnImplThread( void StartCommitOnImplThread(
CompletionEvent* completion, CompletionEvent* completion,
ResourceUpdateQueue* queue, ResourceUpdateQueue* queue,
...@@ -167,8 +169,9 @@ class ThreadProxy : public Proxy, ...@@ -167,8 +169,9 @@ class ThreadProxy : public Proxy,
void LayerTreeHostClosedOnImplThread(CompletionEvent* completion); void LayerTreeHostClosedOnImplThread(CompletionEvent* completion);
void AcquireLayerTexturesForMainThreadOnImplThread( void AcquireLayerTexturesForMainThreadOnImplThread(
CompletionEvent* completion); CompletionEvent* completion);
ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapInternal( DrawSwapReadbackResult DrawSwapReadbackInternal(bool forced_draw,
bool forced_draw); bool swap_requested,
bool readback_requested);
void ForceSerializeOnSwapBuffersOnImplThread(CompletionEvent* completion); void ForceSerializeOnSwapBuffersOnImplThread(CompletionEvent* completion);
void CheckOutputSurfaceStatusOnImplThread(); void CheckOutputSurfaceStatusOnImplThread();
void CommitPendingOnImplThreadForTesting(CommitPendingRequest* request); void CommitPendingOnImplThreadForTesting(CommitPendingRequest* request);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment