diff options
author | pkotwicz@chromium.org <pkotwicz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-29 16:17:55 +0000 |
---|---|---|
committer | pkotwicz@chromium.org <pkotwicz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-29 16:17:55 +0000 |
commit | c155c2541dc88c972115d28be7b66b152a1bedc3 (patch) | |
tree | 4a089075a7d510a4c6d5ce03e11bd8e62095576f /views | |
parent | ea04e3db379d4ad27938969b2dc4b59f9e1db557 (diff) | |
download | chromium_src-c155c2541dc88c972115d28be7b66b152a1bedc3.zip chromium_src-c155c2541dc88c972115d28be7b66b152a1bedc3.tar.gz chromium_src-c155c2541dc88c972115d28be7b66b152a1bedc3.tar.bz2 |
First pass for eliminating double painting
A simple 3D CSS benchmark shows a 20% improvement in framerate on T25 hardware: an increase from about 30 fps to 36 fps.
This is a first pass to getting rid of double painting by introducing a hole in layers Currently a layer which wants its parent not to paint under it will call SetParentLayerHoley
There are a number of questions in terms of implementation:
1) We are doing this with layers. We are currently setting all layers to be holey if the touch_ui flag is enabled. Another option is to merge the holey functionality into regular layers. (Get rid of the holey layer subclass)
2) We are always generating vertices matrix, even in the ui::Layer case, is this ok?
3) We are wasting video memory. We are still uploading a full bitmap. I wasn't able to find a function call which would be able to efficiently slice the bigger bitmap, notably changing the origin of where the painting starts (texture upload)
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@91848 0039d316-1c4b-4281-b951-d872f2087c98
BUG=
TEST=
Review URL: http://codereview.chromium.org/7330025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@94677 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/layer_helper.cc | 1 | ||||
-rw-r--r-- | views/layer_helper.h | 8 | ||||
-rw-r--r-- | views/layer_property_setter.cc | 4 | ||||
-rw-r--r-- | views/view.cc | 21 | ||||
-rw-r--r-- | views/view.h | 6 | ||||
-rw-r--r-- | views/view_unittest.cc | 108 |
6 files changed, 141 insertions, 7 deletions
diff --git a/views/layer_helper.cc b/views/layer_helper.cc index 46cf791..96385fd 100644 --- a/views/layer_helper.cc +++ b/views/layer_helper.cc @@ -14,6 +14,7 @@ namespace internal { LayerHelper::LayerHelper() : bitmap_needs_updating_(true), + fills_bounds_opaquely_(false), layer_updated_externally_(false), paint_to_layer_(false), property_setter_explicitly_set_(false), diff --git a/views/layer_helper.h b/views/layer_helper.h index fa26170..563aa9f 100644 --- a/views/layer_helper.h +++ b/views/layer_helper.h @@ -54,6 +54,12 @@ class LayerHelper { void set_paint_to_layer(bool value) { paint_to_layer_ = value; } bool paint_to_layer() const { return paint_to_layer_; } + // See description in View for details + void set_fills_bounds_opaquely(bool fills_bounds_opaquely) { + fills_bounds_opaquely_ = fills_bounds_opaquely; + } + bool fills_bounds_opaquely() const { return fills_bounds_opaquely_; } + void SetPropertySetter(LayerPropertySetter* setter); LayerPropertySetter* property_setter() { return property_setter_.get(); @@ -97,6 +103,8 @@ class LayerHelper { // Is the layers bitmap out of date? bool bitmap_needs_updating_; + bool fills_bounds_opaquely_; + // If true the bitmap is always up to date. bool layer_updated_externally_; diff --git a/views/layer_property_setter.cc b/views/layer_property_setter.cc index 21b3501..e5b6e94 100644 --- a/views/layer_property_setter.cc +++ b/views/layer_property_setter.cc @@ -41,11 +41,11 @@ void DefaultSetter::Uninstalled(ui::Layer* layer) { void DefaultSetter::SetTransform(ui::Layer* layer, const ui::Transform& transform) { - layer->set_transform(transform); + layer->SetTransform(transform); } void DefaultSetter::SetBounds(ui::Layer* layer, const gfx::Rect& bounds) { - layer->set_bounds(bounds); + layer->SetBounds(bounds); } // AnimatingSetter ------------------------------------------------------------- diff --git a/views/view.cc b/views/view.cc index c6cefcd..480d944 100644 --- a/views/view.cc +++ b/views/view.cc @@ -1205,6 +1205,16 @@ void View::PaintToLayer(const gfx::Rect& dirty_region) { void View::OnWillCompositeLayer() { } +void View::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { + if (!layer_helper_.get()) + layer_helper_.reset(new internal::LayerHelper()); + + layer_helper_->set_fills_bounds_opaquely(fills_bounds_opaquely); + + if (layer()) + layer()->SetFillsBoundsOpaquely(fills_bounds_opaquely); +} + bool View::SetExternalTexture(ui::Texture* texture) { // A little heavy-handed -- it should be that each child has it's own layer. // The desired use case is where there are no children. @@ -1285,7 +1295,7 @@ void View::MoveLayerToParent(ui::Layer* parent_layer, local_point.Offset(x(), y()); if (layer() && parent_layer != layer()) { parent_layer->Add(layer()); - layer()->set_bounds( + layer()->SetBounds( gfx::Rect(local_point.x(), local_point.y(), width(), height())); } else { for (int i = 0, count = child_count(); i < count; ++i) @@ -1730,8 +1740,9 @@ void View::CreateLayer() { DCHECK(ancestor_with_layer || parent_ == NULL); layer_helper_->SetLayer(new ui::Layer(compositor)); - layer()->set_bounds(gfx::Rect(offset.x(), offset.y(), width(), height())); - layer()->set_transform(GetTransform()); + layer()->SetFillsBoundsOpaquely(layer_helper_->fills_bounds_opaquely()); + layer()->SetBounds(gfx::Rect(offset.x(), offset.y(), width(), height())); + layer()->SetTransform(GetTransform()); if (ancestor_with_layer) ancestor_with_layer->layer()->Add(layer()); layer_helper_->set_bitmap_needs_updating(true); @@ -1761,7 +1772,9 @@ void View::DestroyLayer() { if (!layer_helper_.get()) return; - if (!layer_helper_->property_setter_explicitly_set() && !ShouldPaintToLayer()) + if (!layer_helper_->property_setter_explicitly_set() && + !ShouldPaintToLayer() && + !layer_helper_->fills_bounds_opaquely()) layer_helper_.reset(); else layer_helper_->SetLayer(NULL); diff --git a/views/view.h b/views/view.h index 66da529..779059d 100644 --- a/views/view.h +++ b/views/view.h @@ -253,6 +253,12 @@ class VIEWS_API View : public AcceleratorTarget { // Returns whether the view is enabled. virtual bool IsEnabled() const; + // This indicates that the view completely fills its bounds in an opaque + // color. + // This doesn't affect compositing but is a hint to the compositor to optimize + // painting. + void SetFillsBoundsOpaquely(bool fills_bounds_opaquely); + // Transformations ----------------------------------------------------------- // Methods for setting transformations for a view (e.g. rotation, scaling). diff --git a/views/view_unittest.cc b/views/view_unittest.cc index 0309ada..915104f1 100644 --- a/views/view_unittest.cc +++ b/views/view_unittest.cc @@ -2298,6 +2298,10 @@ class TestTexture : public ui::Texture { virtual void SetCanvas(const SkCanvas& canvas, const gfx::Point& origin, const gfx::Size& overall_size) OVERRIDE; + + virtual void Draw(const ui::TextureDrawParams& params, + const gfx::Rect& clip_bounds) OVERRIDE {} + virtual void Draw(const ui::TextureDrawParams& params) OVERRIDE {} private: @@ -2595,7 +2599,7 @@ TEST_F(ViewLayerTest, ResetTransformOnLayerAfterAdd) { EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0)); } -// Makes sure that layer persists after toggling the visibility +// Makes sure that layer persists after toggling the visibility. TEST_F(ViewLayerTest, ToggleVisibilityWithLayer) { View* content_view = new View; widget()->SetContentsView(content_view); @@ -2614,6 +2618,108 @@ TEST_F(ViewLayerTest, ToggleVisibilityWithLayer) { EXPECT_TRUE(v1->layer()); } +// Test that a hole in a layer is correctly created regardless of whether +// the opacity attribute is set before or after the layer is created. +TEST_F(ViewLayerTest, ToggleOpacityWithLayer) { + View* content_view = new View; + widget()->SetContentsView(content_view); + + View* parent_view = new View; + content_view->AddChildView(parent_view); + parent_view->SetPaintToLayer(true); + parent_view->SetBounds(0, 0, 400, 400); + + View* child_view = new View; + child_view->SetBounds(50, 50, 100, 100); + parent_view->AddChildView(child_view); + + // Call SetFillsBoundsOpaquely before layer is created. + ASSERT_TRUE(child_view->layer() == NULL); + child_view->SetFillsBoundsOpaquely(true); + + child_view->SetPaintToLayer(true); + ASSERT_TRUE(child_view->layer()); + EXPECT_EQ( + gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect()); + + child_view->SetFillsBoundsOpaquely(false); + EXPECT_TRUE(parent_view->layer()->hole_rect().IsEmpty()); + + // Call SetFillsBoundsOpaquely after layer is created. + ASSERT_TRUE(parent_view->layer()); + + child_view->SetFillsBoundsOpaquely(true); + EXPECT_EQ( + gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect()); +} + +// Test that a hole in a layer always corresponds to the bounds of opaque +// layers. +TEST_F(ViewLayerTest, MultipleOpaqueLayers) { + View* content_view = new View; + widget()->SetContentsView(content_view); + + View* parent_view = new View; + parent_view->SetPaintToLayer(true); + parent_view->SetBounds(0, 0, 400, 400); + content_view->AddChildView(parent_view); + + View* child_view1 = new View; + child_view1->SetPaintToLayer(true); + child_view1->SetFillsBoundsOpaquely(true); + child_view1->SetBounds(50, 50, 100, 100); + parent_view->AddChildView(child_view1); + + View* child_view2 = new View; + child_view2->SetPaintToLayer(true); + child_view2->SetBounds(150, 150, 200, 200); + parent_view->AddChildView(child_view2); + + // Only child_view1 is opaque + EXPECT_EQ( + gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect()); + + // Both child views are opaque + child_view2->SetFillsBoundsOpaquely(true); + EXPECT_TRUE( + gfx::Rect(50, 50, 100, 100) == parent_view->layer()->hole_rect() || + gfx::Rect(150, 150, 200, 200) == parent_view->layer()->hole_rect()); + + // Only child_view2 is opaque + delete child_view1; + EXPECT_EQ( + gfx::Rect(150, 150, 200, 200), parent_view->layer()->hole_rect()); +} + +// Makes sure that opacity of layer persists after toggling visibilty. +TEST_F(ViewLayerTest, ToggleVisibilityWithOpaqueLayer) { + View* content_view = new View; + widget()->SetContentsView(content_view); + + View* parent_view = new View; + parent_view->SetPaintToLayer(true); + parent_view->SetBounds(0, 0, 400, 400); + content_view->AddChildView(parent_view); + + parent_view->SetPaintToLayer(true); + parent_view->SetBounds(0, 0, 400, 400); + + View* child_view = new View; + child_view->SetBounds(50, 50, 100, 100); + child_view->SetFillsBoundsOpaquely(true); + child_view->SetPaintToLayer(true); + parent_view->AddChildView(child_view); + EXPECT_EQ( + gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect()); + + child_view->SetVisible(false); + EXPECT_TRUE(parent_view->layer()->hole_rect().IsEmpty()); + + child_view->SetVisible(true); + EXPECT_EQ( + gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect()); +} + // Verifies that the complete bounds of a texture are updated if the texture // needs to be refreshed and paint with a clip is invoked. TEST_F(ViewLayerTest, PaintAll) { |