Commit e942c7d1 authored by ajuma@chromium.org's avatar ajuma@chromium.org

Re-raster during scale animations for GPU-rasterized layers without text

This re-rasters GPU-rasterized layers during scale animations in order to
keep content crisp, but only for layers that don't have text (since
re-rastering text at different scales leads to expensive glyph texture
uploads at each scale).

BUG=395760,372391

Review URL: https://codereview.chromium.org/422233008

Cr-Commit-Position: refs/heads/master@{#291068}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@291068 0039d316-1c4b-4281-b951-d872f2087c98
parent 5ad087c0
...@@ -1046,6 +1046,11 @@ bool PictureLayerImpl::ShouldAdjustRasterScale() const { ...@@ -1046,6 +1046,11 @@ bool PictureLayerImpl::ShouldAdjustRasterScale() const {
draw_properties().screen_space_transform_is_animating) draw_properties().screen_space_transform_is_animating)
return true; return true;
if (draw_properties().screen_space_transform_is_animating &&
raster_contents_scale_ != ideal_contents_scale_ &&
ShouldAdjustRasterScaleDuringScaleAnimations())
return true;
bool is_pinching = layer_tree_impl()->PinchGestureActive(); bool is_pinching = layer_tree_impl()->PinchGestureActive();
if (is_pinching && raster_page_scale_) { if (is_pinching && raster_page_scale_) {
// We change our raster scale when it is: // We change our raster scale when it is:
...@@ -1140,11 +1145,12 @@ void PictureLayerImpl::RecalculateRasterScales() { ...@@ -1140,11 +1145,12 @@ void PictureLayerImpl::RecalculateRasterScales() {
raster_contents_scale_ = raster_contents_scale_ =
std::max(raster_contents_scale_, MinimumContentsScale()); std::max(raster_contents_scale_, MinimumContentsScale());
// Since we're not re-rasterizing during animation, rasterize at the maximum // If we're not re-rasterizing during animation, rasterize at the maximum
// scale that will occur during the animation, if the maximum scale is // scale that will occur during the animation, if the maximum scale is
// known. However, to avoid excessive memory use, don't rasterize at a scale // known. However, to avoid excessive memory use, don't rasterize at a scale
// at which this layer would become larger than the viewport. // at which this layer would become larger than the viewport.
if (draw_properties().screen_space_transform_is_animating) { if (draw_properties().screen_space_transform_is_animating &&
!ShouldAdjustRasterScaleDuringScaleAnimations()) {
bool can_raster_at_maximum_scale = false; bool can_raster_at_maximum_scale = false;
if (draw_properties().maximum_animation_contents_scale > 0.f) { if (draw_properties().maximum_animation_contents_scale > 0.f) {
gfx::Size bounds_at_maximum_scale = gfx::ToCeiledSize(gfx::ScaleSize( gfx::Size bounds_at_maximum_scale = gfx::ToCeiledSize(gfx::ScaleSize(
...@@ -1322,6 +1328,22 @@ void PictureLayerImpl::SanityCheckTilingState() const { ...@@ -1322,6 +1328,22 @@ void PictureLayerImpl::SanityCheckTilingState() const {
#endif #endif
} }
bool PictureLayerImpl::ShouldAdjustRasterScaleDuringScaleAnimations() const {
if (!layer_tree_impl()->use_gpu_rasterization())
return false;
// Re-rastering text at different scales using GPU rasterization causes
// texture uploads for glyphs at each scale (see crbug.com/366225). To
// workaround this performance issue, we don't re-rasterize layers with
// text during scale animations.
// TODO(ajuma): Remove this workaround once text can be efficiently
// re-rastered at different scales (e.g. by using distance-field fonts).
if (pile_->has_text())
return false;
return true;
}
float PictureLayerImpl::MaximumTilingContentsScale() const { float PictureLayerImpl::MaximumTilingContentsScale() const {
float max_contents_scale = MinimumContentsScale(); float max_contents_scale = MinimumContentsScale();
for (size_t i = 0; i < tilings_->num_tilings(); ++i) { for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
......
...@@ -184,6 +184,8 @@ class CC_EXPORT PictureLayerImpl ...@@ -184,6 +184,8 @@ class CC_EXPORT PictureLayerImpl
bool CanHaveTilingWithScale(float contents_scale) const; bool CanHaveTilingWithScale(float contents_scale) const;
void SanityCheckTilingState() const; void SanityCheckTilingState() const;
bool ShouldAdjustRasterScaleDuringScaleAnimations() const;
virtual void GetDebugBorderProperties( virtual void GetDebugBorderProperties(
SkColor* color, float* width) const OVERRIDE; SkColor* color, float* width) const OVERRIDE;
virtual void AsValueInto(base::debug::TracedValue* dict) const OVERRIDE; virtual void AsValueInto(base::debug::TracedValue* dict) const OVERRIDE;
......
...@@ -2234,6 +2234,111 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) { ...@@ -2234,6 +2234,111 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 11.f); EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 11.f);
} }
TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForGpuRasterization) {
gfx::Size layer_bounds(100, 100);
gfx::Size viewport_size(1000, 1000);
SetupDefaultTrees(layer_bounds);
host_impl_.SetViewportSize(viewport_size);
host_impl_.SetUseGpuRasterization(true);
float contents_scale = 1.f;
float device_scale = 1.3f;
float page_scale = 1.4f;
float maximum_animation_scale = 1.f;
bool animating_transform = false;
SetContentsScaleOnBothLayers(contents_scale,
device_scale,
page_scale,
maximum_animation_scale,
animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
// Since we're GPU-rasterizing, starting an animation should cause tiling
// resolution to get set to the current contents scale.
animating_transform = true;
contents_scale = 2.f;
maximum_animation_scale = 4.f;
SetContentsScaleOnBothLayers(contents_scale,
device_scale,
page_scale,
maximum_animation_scale,
animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
// Further changes to scale during the animation should cause a new high-res
// tiling to get created.
contents_scale = 3.f;
SetContentsScaleOnBothLayers(contents_scale,
device_scale,
page_scale,
maximum_animation_scale,
animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
// Since we're re-rasterizing during the animation, scales smaller than 1
// should be respected.
contents_scale = 0.25f;
SetContentsScaleOnBothLayers(contents_scale,
device_scale,
page_scale,
maximum_animation_scale,
animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 0.25f);
// Once we stop animating, a new high-res tiling should be created.
contents_scale = 4.f;
animating_transform = false;
SetContentsScaleOnBothLayers(contents_scale,
device_scale,
page_scale,
maximum_animation_scale,
animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
static_cast<FakePicturePileImpl*>(pending_layer_->pile())->set_has_text(true);
static_cast<FakePicturePileImpl*>(active_layer_->pile())->set_has_text(true);
// Since we're GPU-rasterizing but have text, starting an animation should
// cause tiling resolution to get set to the maximum animation scale.
animating_transform = true;
contents_scale = 2.f;
maximum_animation_scale = 3.f;
SetContentsScaleOnBothLayers(contents_scale,
device_scale,
page_scale,
maximum_animation_scale,
animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
// Further changes to scale during the animation should not cause a new
// high-res tiling to get created.
contents_scale = 4.f;
maximum_animation_scale = 5.f;
SetContentsScaleOnBothLayers(contents_scale,
device_scale,
page_scale,
maximum_animation_scale,
animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
// Once we stop animating, a new high-res tiling should be created.
animating_transform = false;
SetContentsScaleOnBothLayers(contents_scale,
device_scale,
page_scale,
maximum_animation_scale,
animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
}
TEST_F(PictureLayerImplTest, LayerRasterTileIterator) { TEST_F(PictureLayerImplTest, LayerRasterTileIterator) {
gfx::Size tile_size(100, 100); gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000); gfx::Size layer_bounds(1000, 1000);
......
...@@ -217,6 +217,11 @@ bool Picture::IsSuitableForGpuRasterization() const { ...@@ -217,6 +217,11 @@ bool Picture::IsSuitableForGpuRasterization() const {
return picture_->suitableForGpuRasterization(NULL); return picture_->suitableForGpuRasterization(NULL);
} }
bool Picture::HasText() const {
DCHECK(picture_);
return picture_->hasText();
}
void Picture::CloneForDrawing(int num_threads) { void Picture::CloneForDrawing(int num_threads) {
TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads);
......
...@@ -75,6 +75,8 @@ class CC_EXPORT Picture ...@@ -75,6 +75,8 @@ class CC_EXPORT Picture
bool IsSuitableForGpuRasterization() const; bool IsSuitableForGpuRasterization() const;
bool HasText() const;
// Apply this scale and raster the negated region into the canvas. // Apply this scale and raster the negated region into the canvas.
// |negated_content_region| specifies the region to be clipped out of the // |negated_content_region| specifies the region to be clipped out of the
// raster operation, i.e., the parts of the canvas which will not get drawn // raster operation, i.e., the parts of the canvas which will not get drawn
......
...@@ -371,6 +371,7 @@ bool PicturePile::UpdateAndExpandInvalidation( ...@@ -371,6 +371,7 @@ bool PicturePile::UpdateAndExpandInvalidation(
// the pile after each invalidation. // the pile after each invalidation.
is_suitable_for_gpu_rasterization_ &= is_suitable_for_gpu_rasterization_ &=
picture->IsSuitableForGpuRasterization(); picture->IsSuitableForGpuRasterization();
has_text_ |= picture->HasText();
base::TimeDelta duration = base::TimeDelta duration =
stats_instrumentation->EndRecording(start_time); stats_instrumentation->EndRecording(start_time);
best_duration = std::min(duration, best_duration); best_duration = std::min(duration, best_duration);
......
...@@ -47,7 +47,8 @@ PicturePileBase::PicturePileBase() ...@@ -47,7 +47,8 @@ PicturePileBase::PicturePileBase()
contents_fill_bounds_completely_(false), contents_fill_bounds_completely_(false),
show_debug_picture_borders_(false), show_debug_picture_borders_(false),
clear_canvas_with_debug_color_(kDefaultClearCanvasSetting), clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
has_any_recordings_(false) { has_any_recordings_(false),
has_text_(false) {
tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize)); tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
tile_grid_info_.fTileInterval.setEmpty(); tile_grid_info_.fTileInterval.setEmpty();
tile_grid_info_.fMargin.setEmpty(); tile_grid_info_.fMargin.setEmpty();
...@@ -67,7 +68,9 @@ PicturePileBase::PicturePileBase(const PicturePileBase* other) ...@@ -67,7 +68,9 @@ PicturePileBase::PicturePileBase(const PicturePileBase* other)
contents_fill_bounds_completely_(other->contents_fill_bounds_completely_), contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
show_debug_picture_borders_(other->show_debug_picture_borders_), show_debug_picture_borders_(other->show_debug_picture_borders_),
clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
has_any_recordings_(other->has_any_recordings_) {} has_any_recordings_(other->has_any_recordings_),
has_text_(other->has_text_) {
}
PicturePileBase::PicturePileBase(const PicturePileBase* other, PicturePileBase::PicturePileBase(const PicturePileBase* other,
unsigned thread_index) unsigned thread_index)
...@@ -82,7 +85,8 @@ PicturePileBase::PicturePileBase(const PicturePileBase* other, ...@@ -82,7 +85,8 @@ PicturePileBase::PicturePileBase(const PicturePileBase* other,
contents_fill_bounds_completely_(other->contents_fill_bounds_completely_), contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
show_debug_picture_borders_(other->show_debug_picture_borders_), show_debug_picture_borders_(other->show_debug_picture_borders_),
clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
has_any_recordings_(other->has_any_recordings_) { has_any_recordings_(other->has_any_recordings_),
has_text_(other->has_text_) {
for (PictureMap::const_iterator it = other->picture_map_.begin(); for (PictureMap::const_iterator it = other->picture_map_.begin();
it != other->picture_map_.end(); it != other->picture_map_.end();
++it) { ++it) {
......
...@@ -49,6 +49,9 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { ...@@ -49,6 +49,9 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> {
// If this pile contains any valid recordings. May have false positives. // If this pile contains any valid recordings. May have false positives.
bool HasRecordings() const { return has_any_recordings_; } bool HasRecordings() const { return has_any_recordings_; }
// If this pile has ever contained any recordings with text.
bool has_text() const { return has_text_; }
static void ComputeTileGridInfo(const gfx::Size& tile_grid_size, static void ComputeTileGridInfo(const gfx::Size& tile_grid_size,
SkTileGridFactory::TileGridInfo* info); SkTileGridFactory::TileGridInfo* info);
...@@ -117,6 +120,7 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> { ...@@ -117,6 +120,7 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> {
// A hint about whether there are any recordings. This may be a false // A hint about whether there are any recordings. This may be a false
// positive. // positive.
bool has_any_recordings_; bool has_any_recordings_;
bool has_text_;
private: private:
void SetBufferPixels(int buffer_pixels); void SetBufferPixels(int buffer_pixels);
......
...@@ -68,6 +68,8 @@ class FakePicturePileImpl : public PicturePileImpl { ...@@ -68,6 +68,8 @@ class FakePicturePileImpl : public PicturePileImpl {
clear_canvas_with_debug_color_ = clear; clear_canvas_with_debug_color_ = clear;
} }
void set_has_text(bool has_text) { has_text_ = has_text; }
protected: protected:
FakePicturePileImpl(); FakePicturePileImpl();
virtual ~FakePicturePileImpl(); virtual ~FakePicturePileImpl();
......
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