summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorenne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-01 01:10:23 +0000
committerenne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-01 01:10:23 +0000
commit3d609bb151bd56012f77f752805d4b53b69727d0 (patch)
treeb610b81524e5e3f26cf7e7b5605a4f75d16f252f /cc
parent5353945a7a1c5c0b0b07976a073b63d7e32b1807 (diff)
downloadchromium_src-3d609bb151bd56012f77f752805d4b53b69727d0.zip
chromium_src-3d609bb151bd56012f77f752805d4b53b69727d0.tar.gz
chromium_src-3d609bb151bd56012f77f752805d4b53b69727d0.tar.bz2
cc: Prevent drawing low res tiles after visibility change
BUG=335289 Review URL: https://codereview.chromium.org/143903012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@248320 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r--cc/layers/picture_layer_impl.cc1
-rw-r--r--cc/layers/picture_layer_impl_unittest.cc21
-rw-r--r--cc/scheduler/draw_swap_readback_result.h1
-rw-r--r--cc/scheduler/scheduler_state_machine.cc7
-rw-r--r--cc/scheduler/scheduler_state_machine_unittest.cc33
-rw-r--r--cc/trees/layer_tree_host_impl.cc11
-rw-r--r--cc/trees/layer_tree_host_impl_unittest.cc149
-rw-r--r--cc/trees/layer_tree_impl.cc20
-rw-r--r--cc/trees/layer_tree_impl.h5
9 files changed, 222 insertions, 26 deletions
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 0826186f..b5342df 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -756,6 +756,7 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
// them and only allow activating to high res tiles, since tiles on each layer
// will be in different places on screen.
if (!twin_high_res || !twin_low_res ||
+ twin_layer_->layer_tree_impl()->RequiresHighResToDraw() ||
draw_properties().screen_space_transform !=
twin_layer_->draw_properties().screen_space_transform) {
twin_high_res = NULL;
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index c3b569d..9a6a25b 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -1276,6 +1276,27 @@ TEST_F(PictureLayerImplTest, HighResRequiredWhenUnsharedActiveAllReady) {
AssertNoTilesRequired(pending_layer_->LowResTiling());
}
+TEST_F(PictureLayerImplTest, HighResRequiredWhenMissingHighResFlagOn) {
+ gfx::Size layer_bounds(400, 400);
+ gfx::Size tile_size(100, 100);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
+
+ // All tiles shared (no invalidation).
+ CreateHighLowResAndSetAllTilesVisible();
+
+ // Verify active tree not ready.
+ Tile* some_active_tile =
+ active_layer_->HighResTiling()->AllTilesForTesting()[0];
+ EXPECT_FALSE(some_active_tile->IsReadyToDraw());
+
+ // When high res are required, even if the active tree is not ready,
+ // the high res tiles must be ready.
+ host_impl_.active_tree()->SetRequiresHighResToDraw();
+ pending_layer_->MarkVisibleResourcesAsRequired();
+ AssertAllTilesRequired(pending_layer_->HighResTiling());
+ AssertNoTilesRequired(pending_layer_->LowResTiling());
+}
+
TEST_F(PictureLayerImplTest, NothingRequiredIfAllHighResTilesShared) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
diff --git a/cc/scheduler/draw_swap_readback_result.h b/cc/scheduler/draw_swap_readback_result.h
index 7bcf3df..8b875a4 100644
--- a/cc/scheduler/draw_swap_readback_result.h
+++ b/cc/scheduler/draw_swap_readback_result.h
@@ -12,6 +12,7 @@ struct DrawSwapReadbackResult {
INVALID_RESULT,
DRAW_SUCCESS,
DRAW_ABORTED_CHECKERBOARD_ANIMATIONS,
+ DRAW_ABORTED_MISSING_HIGH_RES_CONTENT,
};
DrawSwapReadbackResult()
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 36397e1..b4b682d 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -1051,6 +1051,13 @@ void SchedulerStateMachine::DidDrawIfPossibleCompleted(
forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
}
break;
+ case DrawSwapReadbackResult::DRAW_ABORTED_MISSING_HIGH_RES_CONTENT:
+ // It's not clear whether this missing content is because of missing
+ // pictures (which requires a commit) or because of memory pressure
+ // removing textures (which might not). To be safe, request a commit
+ // anyway.
+ needs_commit_ = true;
+ break;
}
}
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index 4fbc224..0a983de 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -174,7 +174,7 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
}
TEST(SchedulerStateMachineTest,
- TestFailedDrawSetsNeedsCommitAndDoesNotDrawAgain) {
+ TestFailedDrawForAnimationCheckerboardSetsNeedsCommitAndDoesNotDrawAgain) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetCanStart();
@@ -207,6 +207,37 @@ TEST(SchedulerStateMachineTest,
EXPECT_TRUE(state.CommitPending());
}
+TEST(SchedulerStateMachineTest, TestFailedDrawForMissingHighResDoesNothing) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetVisible(true);
+ state.SetCanDraw(true);
+ state.SetNeedsRedraw(true);
+ EXPECT_TRUE(state.RedrawPending());
+ EXPECT_TRUE(state.BeginImplFrameNeeded());
+
+ state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_FALSE(state.RedrawPending());
+ EXPECT_FALSE(state.CommitPending());
+
+ // Missing high res content requires a commit (but not a redraw)
+ state.DidDrawIfPossibleCompleted(
+ DrawSwapReadbackResult::DRAW_ABORTED_MISSING_HIGH_RES_CONTENT);
+ state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_FALSE(state.RedrawPending());
+ EXPECT_TRUE(state.CommitPending());
+}
+
TEST(SchedulerStateMachineTest,
TestsetNeedsRedrawDuringFailedDrawDoesNotRemoveNeedsRedraw) {
SchedulerSettings default_scheduler_settings;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index aff8a76..f23bceb 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -871,8 +871,12 @@ DrawSwapReadbackResult::DrawResult LayerTreeHostImpl::CalculateRenderPasses(
}
}
- if (append_quads_data.had_incomplete_tile)
+ if (append_quads_data.had_incomplete_tile) {
frame->contains_incomplete_tile = true;
+ if (active_tree()->RequiresHighResToDraw())
+ draw_result =
+ DrawSwapReadbackResult::DRAW_ABORTED_MISSING_HIGH_RES_CONTENT;
+ }
occlusion_tracker.LeaveLayer(it);
}
@@ -1460,6 +1464,7 @@ LayerTreeHostImpl::GetRendererCapabilities() const {
}
bool LayerTreeHostImpl::SwapBuffers(const LayerTreeHostImpl::FrameData& frame) {
+ active_tree()->ResetRequiresHighResToDraw();
if (frame.has_no_damage) {
active_tree()->BreakSwapPromises(SwapPromise::SWAP_FAILS);
return false;
@@ -1640,8 +1645,10 @@ void LayerTreeHostImpl::SetVisible(bool visible) {
DidVisibilityChange(this, visible_);
EnforceManagedMemoryPolicy(ActualManagedMemoryPolicy());
- if (!visible_)
+ if (!visible_) {
+ active_tree()->SetRequiresHighResToDraw();
EvictAllUIResources();
+ }
// Evict tiles immediately if invisible since this tab may never get another
// draw or timer tick.
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index af8d2db..29a1afb 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -14,6 +14,7 @@
#include "cc/base/latency_info_swap_promise.h"
#include "cc/base/math_util.h"
#include "cc/input/top_controls_manager.h"
+#include "cc/layers/append_quads_data.h"
#include "cc/layers/delegated_renderer_layer_impl.h"
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/layers/io_surface_layer_impl.h"
@@ -1433,6 +1434,7 @@ TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) {
}
}
+// TODO(enne): Convert this to PictureLayerImpl
class DidDrawCheckLayer : public TiledLayerImpl {
public:
static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
@@ -1680,6 +1682,13 @@ class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
resource_provider));
}
+ virtual void AppendQuads(QuadSink* quad_sink,
+ AppendQuadsData* append_quads_data) OVERRIDE {
+ TiledLayerImpl::AppendQuads(quad_sink, append_quads_data);
+ if (tile_missing_)
+ append_quads_data->had_incomplete_tile = true;
+ }
+
private:
MissingTextureAnimatingLayer(LayerTreeImpl* tree_impl,
int id,
@@ -1687,7 +1696,7 @@ class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
bool skips_draw,
bool animating,
ResourceProvider* resource_provider)
- : DidDrawCheckLayer(tree_impl, id) {
+ : DidDrawCheckLayer(tree_impl, id), tile_missing_(tile_missing) {
scoped_ptr<LayerTilingData> tiling_data =
LayerTilingData::Create(gfx::Size(10, 10),
LayerTilingData::NO_BORDER_TEXELS);
@@ -1706,20 +1715,25 @@ class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
if (animating)
AddAnimatedTransformToLayer(this, 10.0, 3, 0);
}
+
+ bool tile_missing_;
};
-TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) {
- // When the texture is not missing, we draw as usual.
+TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsWhenNoTexturesMissing) {
host_impl_->active_tree()->SetRootLayer(
DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
DidDrawCheckLayer* root =
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+
+ bool tile_missing = false;
+ bool skips_draw = false;
+ bool is_animating = false;
root->AddChild(
MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
2,
- false,
- false,
- true,
+ tile_missing,
+ skips_draw,
+ is_animating,
host_impl_->resource_provider()));
LayerTreeHostImpl::FrameData frame;
@@ -1728,59 +1742,152 @@ TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) {
host_impl_->PrepareToDraw(&frame, gfx::Rect()));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
+}
+
+TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsWithAnimatedLayer) {
+ host_impl_->active_tree()->SetRootLayer(
+ DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
+ DidDrawCheckLayer* root =
+ static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = false;
+ bool skips_draw = false;
+ bool is_animating = true;
+ root->AddChild(
+ MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
+ 2,
+ tile_missing,
+ skips_draw,
+ is_animating,
+ host_impl_->resource_provider()));
+ LayerTreeHostImpl::FrameData frame;
+
+ EXPECT_EQ(DrawSwapReadbackResult::DRAW_SUCCESS,
+ host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DidDrawAllLayers(frame);
+}
+
+TEST_F(LayerTreeHostImplTest,
+ PrepareToDrawSucceedsWithNonAnimatedMissingTexture) {
// When a texture is missing and we're not animating, we draw as usual with
// checkerboarding.
host_impl_->active_tree()->SetRootLayer(
DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
- root =
+ DidDrawCheckLayer* root =
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+
+ bool tile_missing = true;
+ bool skips_draw = false;
+ bool is_animating = false;
root->AddChild(
MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
4,
- true,
- false,
- false,
+ tile_missing,
+ skips_draw,
+ is_animating,
host_impl_->resource_provider()));
-
+ LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DrawSwapReadbackResult::DRAW_SUCCESS,
host_impl_->PrepareToDraw(&frame, gfx::Rect()));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
+}
+TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) {
// When a texture is missing and we're animating, we don't want to draw
// anything.
host_impl_->active_tree()->SetRootLayer(
DidDrawCheckLayer::Create(host_impl_->active_tree(), 5));
- root =
+ DidDrawCheckLayer* root =
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = true;
+ bool skips_draw = false;
+ bool is_animating = true;
root->AddChild(
MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
6,
- true,
- false,
- true,
+ tile_missing,
+ skips_draw,
+ is_animating,
host_impl_->resource_provider()));
-
+ LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS,
host_impl_->PrepareToDraw(&frame, gfx::Rect()));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
+}
+
+TEST_F(LayerTreeHostImplTest,
+ PrepareToDrawSucceedsWithMissingSkippedAnimatedLayer) {
+ // When the layer skips draw and we're animating, we still draw the frame.
+ host_impl_->active_tree()->SetRootLayer(
+ DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
+ DidDrawCheckLayer* root =
+ static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = false;
+ bool skips_draw = true;
+ bool is_animating = true;
+ root->AddChild(
+ MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
+ 8,
+ tile_missing,
+ skips_draw,
+ is_animating,
+ host_impl_->resource_provider()));
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(host_impl_->PrepareToDraw(&frame, gfx::Rect()),
+ DrawSwapReadbackResult::DRAW_SUCCESS);
+ host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DidDrawAllLayers(frame);
+}
+TEST_F(LayerTreeHostImplTest,
+ PrepareToDrawSucceedsWhenHighResRequiredButNoMissingTextures) {
// When the layer skips draw and we're animating, we still draw the frame.
host_impl_->active_tree()->SetRootLayer(
DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
- root =
+ DidDrawCheckLayer* root =
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = false;
+ bool skips_draw = false;
+ bool is_animating = false;
root->AddChild(
MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
8,
- false,
- true,
- true,
+ tile_missing,
+ skips_draw,
+ is_animating,
host_impl_->resource_provider()));
+ host_impl_->active_tree()->SetRequiresHighResToDraw();
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(host_impl_->PrepareToDraw(&frame, gfx::Rect()),
+ DrawSwapReadbackResult::DRAW_SUCCESS);
+ host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DidDrawAllLayers(frame);
+}
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+TEST_F(LayerTreeHostImplTest,
+ PrepareToDrawFailsWhenHighResRequiredAndMissingTextures) {
+ // When the layer skips draw and we're animating, we still draw the frame.
+ host_impl_->active_tree()->SetRootLayer(
+ DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
+ DidDrawCheckLayer* root =
+ static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = true;
+ bool skips_draw = false;
+ bool is_animating = false;
+ root->AddChild(
+ MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
+ 8,
+ tile_missing,
+ skips_draw,
+ is_animating,
+ host_impl_->resource_provider()));
+ host_impl_->active_tree()->SetRequiresHighResToDraw();
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(host_impl_->PrepareToDraw(&frame, gfx::Rect()),
+ DrawSwapReadbackResult::DRAW_ABORTED_MISSING_HIGH_RES_CONTENT);
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
}
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index f892d8d..85b500f 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -90,11 +90,11 @@ LayerTreeImpl::LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl)
max_page_scale_factor_(0),
scrolling_layer_id_from_previous_tree_(0),
contents_textures_purged_(false),
+ requires_high_res_to_draw_(false),
viewport_size_invalid_(false),
needs_update_draw_properties_(true),
needs_full_tree_sync_(true),
- next_activation_forces_redraw_(false) {
-}
+ next_activation_forces_redraw_(false) {}
LayerTreeImpl::~LayerTreeImpl() {
// Need to explicitly clear the tree prior to destroying this so that
@@ -217,6 +217,10 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
else
target_tree->ResetContentsTexturesPurged();
+ // Always reset this flag on activation, as we would only have activated
+ // if we were in a good state.
+ target_tree->ResetRequiresHighResToDraw();
+
if (ViewportSizeInvalid())
target_tree->SetViewportSizeInvalid();
else
@@ -564,6 +568,18 @@ void LayerTreeImpl::ResetContentsTexturesPurged() {
layer_tree_host_impl_->OnCanDrawStateChangedForTree();
}
+void LayerTreeImpl::SetRequiresHighResToDraw() {
+ requires_high_res_to_draw_ = true;
+}
+
+void LayerTreeImpl::ResetRequiresHighResToDraw() {
+ requires_high_res_to_draw_ = false;
+}
+
+bool LayerTreeImpl::RequiresHighResToDraw() const {
+ return requires_high_res_to_draw_;
+}
+
bool LayerTreeImpl::ViewportSizeInvalid() const {
return viewport_size_invalid_;
}
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 81a8992..47bb6f0 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -203,6 +203,10 @@ class CC_EXPORT LayerTreeImpl {
void SetContentsTexturesPurged();
void ResetContentsTexturesPurged();
+ void SetRequiresHighResToDraw();
+ void ResetRequiresHighResToDraw();
+ bool RequiresHighResToDraw() const;
+
// Set on the active tree when the viewport size recently changed
// and the active tree's size is now out of date.
bool ViewportSizeInvalid() const;
@@ -278,6 +282,7 @@ class CC_EXPORT LayerTreeImpl {
LayerImplList render_surface_layer_list_;
bool contents_textures_purged_;
+ bool requires_high_res_to_draw_;
bool viewport_size_invalid_;
bool needs_update_draw_properties_;