diff options
author | alokp@chromium.org <alokp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-10 15:12:15 +0000 |
---|---|---|
committer | alokp@chromium.org <alokp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-10 15:12:15 +0000 |
commit | 6a41ea0c15f7f1512cd440f5e1e266ec23a959a4 (patch) | |
tree | 165503066a2a3d2eb54d330adb50238c09000bbc /cc | |
parent | bca53b0d57b74ad40aca5b37f0223e7dcf3bc8f7 (diff) | |
download | chromium_src-6a41ea0c15f7f1512cd440f5e1e266ec23a959a4.zip chromium_src-6a41ea0c15f7f1512cd440f5e1e266ec23a959a4.tar.gz chromium_src-6a41ea0c15f7f1512cd440f5e1e266ec23a959a4.tar.bz2 |
cc: Let skia veto gpu rasterization.
Once gpu rasterization is disabled on a layer, it will stay disabled.
BUG=329722
Review URL: https://codereview.chromium.org/222903005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@262994 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r-- | cc/layers/picture_layer.cc | 40 | ||||
-rw-r--r-- | cc/layers/picture_layer.h | 7 | ||||
-rw-r--r-- | cc/layers/picture_layer_impl.cc | 26 | ||||
-rw-r--r-- | cc/layers/picture_layer_impl.h | 6 | ||||
-rw-r--r-- | cc/layers/picture_layer_impl_unittest.cc | 116 | ||||
-rw-r--r-- | cc/layers/picture_layer_unittest.cc | 83 | ||||
-rw-r--r-- | cc/resources/picture.cc | 13 | ||||
-rw-r--r-- | cc/resources/picture.h | 2 | ||||
-rw-r--r-- | cc/resources/picture_pile.cc | 11 | ||||
-rw-r--r-- | cc/resources/picture_pile.h | 9 |
10 files changed, 184 insertions, 129 deletions
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc index dee9a78..e47f4b8 100644 --- a/cc/layers/picture_layer.cc +++ b/cc/layers/picture_layer.cc @@ -20,7 +20,7 @@ PictureLayer::PictureLayer(ContentLayerClient* client) pile_(make_scoped_refptr(new PicturePile())), instrumentation_object_tracker_(id()), is_mask_(false), - has_gpu_rasterization_hint_(false), + has_gpu_rasterization_hint_(TRIBOOL_UNKNOWN), update_source_frame_number_(-1) {} PictureLayer::~PictureLayer() { @@ -50,7 +50,7 @@ void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) { } layer_impl->SetIsMask(is_mask_); - layer_impl->SetHasGpuRasterizationHint(has_gpu_rasterization_hint_); + layer_impl->SetUseGpuRasterization(ShouldUseGpuRasterization()); // Unlike other properties, invalidation must always be set on layer_impl. // See PictureLayerImpl::PushPropertiesTo for more details. @@ -138,11 +138,37 @@ void PictureLayer::SetIsMask(bool is_mask) { } void PictureLayer::SetHasGpuRasterizationHint(bool has_hint) { - DCHECK(IsPropertyChangeAllowed()); - if (has_gpu_rasterization_hint_ == has_hint) - return; - has_gpu_rasterization_hint_ = has_hint; - SetNeedsCommit(); + switch (has_gpu_rasterization_hint_) { + case TRIBOOL_UNKNOWN: // Fall-through. + case TRIBOOL_TRUE: + has_gpu_rasterization_hint_ = has_hint ? TRIBOOL_TRUE : TRIBOOL_FALSE; + break; + case TRIBOOL_FALSE: + // GPU rasterization cannot be enabled once disabled. + // This is done to prevent frequent invalidations and visual flashing. + break; + default: + NOTREACHED(); + } + // No need to set needs commit or push-properties. + // If only the hint changes and the layer is still valid, there is no need + // to invalidate the rasterization for the whole layer. If there is an + // invalidation (current or future) we will re-raster everything so that it + // is consistent across the layer. +} + +bool PictureLayer::ShouldUseGpuRasterization() const { + switch (layer_tree_host()->settings().rasterization_site) { + case LayerTreeSettings::CpuRasterization: + return false; + case LayerTreeSettings::HybridRasterization: + return has_gpu_rasterization_hint_ == TRIBOOL_TRUE && + pile_->is_suitable_for_gpu_rasterization(); + case LayerTreeSettings::GpuRasterization: + return true; + } + NOTREACHED(); + return false; } bool PictureLayer::SupportsLCDText() const { diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h index 78bb8f4..28f4f90 100644 --- a/cc/layers/picture_layer.h +++ b/cc/layers/picture_layer.h @@ -41,6 +41,9 @@ class CC_EXPORT PictureLayer : public Layer { ContentLayerClient* client() { return client_; } void SetHasGpuRasterizationHint(bool has_hint); + bool ShouldUseGpuRasterization() const; + + PicturePile* GetPicturePileForTesting() const { return pile_.get(); } protected: explicit PictureLayer(ContentLayerClient* client); @@ -57,7 +60,9 @@ class CC_EXPORT PictureLayer : public Layer { Region pile_invalidation_; gfx::Rect last_updated_visible_content_rect_; bool is_mask_; - bool has_gpu_rasterization_hint_; + + enum TriBool { TRIBOOL_UNKNOWN, TRIBOOL_FALSE, TRIBOOL_TRUE }; + TriBool has_gpu_rasterization_hint_; int update_source_frame_number_; diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index 57becf43..7dac994 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc @@ -54,8 +54,8 @@ PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id) is_using_lcd_text_(tree_impl->settings().can_use_lcd_text), needs_post_commit_initialization_(true), should_update_tile_priorities_(false), - has_gpu_rasterization_hint_(false), should_use_low_res_tiling_(tree_impl->settings().create_low_res_tiling), + use_gpu_rasterization_(false), layer_needs_to_register_itself_(true) {} PictureLayerImpl::~PictureLayerImpl() { @@ -96,7 +96,7 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) { layer_impl->SetIsMask(is_mask_); layer_impl->pile_ = pile_; - layer_impl->SetHasGpuRasterizationHint(has_gpu_rasterization_hint_); + layer_impl->use_gpu_rasterization_ = use_gpu_rasterization_; // Tilings would be expensive to push, so we swap. layer_impl->tilings_.swap(tilings_); @@ -490,24 +490,12 @@ skia::RefPtr<SkPicture> PictureLayerImpl::GetPicture() { return pile_->GetFlattenedPicture(); } -void PictureLayerImpl::SetHasGpuRasterizationHint(bool has_hint) { - bool old_should_use_gpu_rasterization = ShouldUseGpuRasterization(); - has_gpu_rasterization_hint_ = has_hint; - if (ShouldUseGpuRasterization() != old_should_use_gpu_rasterization) - RemoveAllTilings(); -} +void PictureLayerImpl::SetUseGpuRasterization(bool use_gpu) { + if (use_gpu_rasterization_ == use_gpu) + return; -bool PictureLayerImpl::ShouldUseGpuRasterization() const { - switch (layer_tree_impl()->settings().rasterization_site) { - case LayerTreeSettings::CpuRasterization: - return false; - case LayerTreeSettings::HybridRasterization: - return has_gpu_rasterization_hint_; - case LayerTreeSettings::GpuRasterization: - return true; - } - NOTREACHED(); - return false; + use_gpu_rasterization_ = use_gpu; + RemoveAllTilings(); } scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling, diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h index b9a04ea..dc171fc 100644 --- a/cc/layers/picture_layer_impl.h +++ b/cc/layers/picture_layer_impl.h @@ -129,8 +129,8 @@ class CC_EXPORT PictureLayerImpl virtual void RunMicroBenchmark(MicroBenchmarkImpl* benchmark) OVERRIDE; - void SetHasGpuRasterizationHint(bool has_hint); - bool ShouldUseGpuRasterization() const; + void SetUseGpuRasterization(bool use_gpu); + bool ShouldUseGpuRasterization() const { return use_gpu_rasterization_; } // Functions used by tile manager. void DidUnregisterLayer(); @@ -208,8 +208,8 @@ class CC_EXPORT PictureLayerImpl // A sanity state check to make sure UpdateTilePriorities only gets called // after a CalculateContentsScale/ManageTilings. bool should_update_tile_priorities_; - bool has_gpu_rasterization_hint_; bool should_use_low_res_tiling_; + bool use_gpu_rasterization_; bool layer_needs_to_register_itself_; diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 6cdd577..15a439c 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc @@ -18,8 +18,6 @@ #include "cc/test/fake_picture_layer_impl.h" #include "cc/test/fake_picture_pile_impl.h" #include "cc/test/geometry_test_utils.h" -#include "cc/test/gpu_rasterization_settings.h" -#include "cc/test/hybrid_rasterization_settings.h" #include "cc/test/impl_side_painting_settings.h" #include "cc/test/mock_quad_culler.h" #include "cc/test/test_shared_bitmap_manager.h" @@ -1634,7 +1632,7 @@ TEST_F(PictureLayerImplTest, SyncTilingAfterReleaseResource) { EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution()); } -TEST_F(PictureLayerImplTest, TilingWithoutGpuRasterization) { +TEST_F(PictureLayerImplTest, NoLowResTilingWithGpuRasterization) { gfx::Size default_tile_size(host_impl_.settings().default_tile_size); gfx::Size layer_bounds(default_tile_size.width() * 4, default_tile_size.height() * 4); @@ -1654,6 +1652,20 @@ TEST_F(PictureLayerImplTest, TilingWithoutGpuRasterization) { &result_bounds); // Should have a low-res and a high-res tiling. ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings()); + + pending_layer_->SetUseGpuRasterization(true); + EXPECT_TRUE(pending_layer_->ShouldUseGpuRasterization()); + EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings()); + pending_layer_->CalculateContentsScale(1.f, + 1.f, + 1.f, + 1.f, + false, + &result_scale_x, + &result_scale_y, + &result_bounds); + // Should only have the high-res tiling. + ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings()); } TEST_F(PictureLayerImplTest, NoTilingIfDoesNotDrawContent) { @@ -1768,54 +1780,9 @@ TEST_F(DeferredInitPictureLayerImplTest, host_impl_.active_tree()->UpdateDrawProperties(); } -class HybridRasterizationPictureLayerImplTest : public PictureLayerImplTest { - public: - HybridRasterizationPictureLayerImplTest() - : PictureLayerImplTest(HybridRasterizationSettings()) {} -}; - -TEST_F(HybridRasterizationPictureLayerImplTest, Tiling) { - gfx::Size default_tile_size(host_impl_.settings().default_tile_size); - gfx::Size layer_bounds(default_tile_size.width() * 4, - default_tile_size.height() * 4); - float result_scale_x, result_scale_y; - gfx::Size result_bounds; - - SetupDefaultTrees(layer_bounds); - EXPECT_FALSE(pending_layer_->ShouldUseGpuRasterization()); - EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings()); - pending_layer_->CalculateContentsScale(1.f, - 1.f, - 1.f, - 1.f, - false, - &result_scale_x, - &result_scale_y, - &result_bounds); - // Should have a low-res and a high-res tiling. - ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings()); - - pending_layer_->SetHasGpuRasterizationHint(true); - EXPECT_TRUE(pending_layer_->ShouldUseGpuRasterization()); - EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings()); - pending_layer_->CalculateContentsScale(1.f, - 1.f, - 1.f, - 1.f, - false, - &result_scale_x, - &result_scale_y, - &result_bounds); - // Should only have the high-res tiling. - ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings()); -} - -TEST_F(HybridRasterizationPictureLayerImplTest, - HighResTilingDuringAnimationForCpuRasterization) { +TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) { gfx::Size tile_size(host_impl_.settings().default_tile_size); SetupDefaultTrees(tile_size); - pending_layer_->SetHasGpuRasterizationHint(false); - active_layer_->SetHasGpuRasterizationHint(false); float contents_scale = 1.f; float device_scale = 1.3f; @@ -1901,12 +1868,11 @@ TEST_F(HybridRasterizationPictureLayerImplTest, EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f); } -TEST_F(HybridRasterizationPictureLayerImplTest, - HighResTilingDuringAnimationForGpuRasterization) { +TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForGpuRasterization) { gfx::Size tile_size(host_impl_.settings().default_tile_size); SetupDefaultTrees(tile_size); - pending_layer_->SetHasGpuRasterizationHint(true); - active_layer_->SetHasGpuRasterizationHint(true); + pending_layer_->SetUseGpuRasterization(true); + active_layer_->SetUseGpuRasterization(true); float contents_scale = 1.f; float device_scale = 1.f; @@ -1956,50 +1922,6 @@ TEST_F(HybridRasterizationPictureLayerImplTest, EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f); } -class GpuRasterizationPictureLayerImplTest : public PictureLayerImplTest { - public: - GpuRasterizationPictureLayerImplTest() - : PictureLayerImplTest(GpuRasterizationSettings()) {} -}; - -TEST_F(GpuRasterizationPictureLayerImplTest, Tiling) { - gfx::Size default_tile_size(host_impl_.settings().default_tile_size); - gfx::Size layer_bounds(default_tile_size.width() * 4, - default_tile_size.height() * 4); - float result_scale_x, result_scale_y; - gfx::Size result_bounds; - - SetupDefaultTrees(layer_bounds); - pending_layer_->SetHasGpuRasterizationHint(true); - EXPECT_TRUE(pending_layer_->ShouldUseGpuRasterization()); - EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings()); - pending_layer_->CalculateContentsScale(1.f, - 1.f, - 1.f, - 1.f, - false, - &result_scale_x, - &result_scale_y, - &result_bounds); - // Should only have the high-res tiling. - ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings()); - - pending_layer_->SetHasGpuRasterizationHint(false); - EXPECT_TRUE(pending_layer_->ShouldUseGpuRasterization()); - // Should still have the high-res tiling. - EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings()); - pending_layer_->CalculateContentsScale(1.f, - 1.f, - 1.f, - 1.f, - false, - &result_scale_x, - &result_scale_y, - &result_bounds); - // Should still only have the high-res tiling. - ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings()); -} - TEST_F(PictureLayerImplTest, LayerRasterTileIterator) { gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1000, 1000); diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc index 3ff1de5..5df3449 100644 --- a/cc/layers/picture_layer_unittest.cc +++ b/cc/layers/picture_layer_unittest.cc @@ -10,6 +10,8 @@ #include "cc/test/fake_layer_tree_host.h" #include "cc/test/fake_picture_layer_impl.h" #include "cc/test/fake_proxy.h" +#include "cc/test/gpu_rasterization_settings.h" +#include "cc/test/hybrid_rasterization_settings.h" #include "cc/test/impl_side_painting_settings.h" #include "cc/trees/occlusion_tracker.h" #include "cc/trees/single_thread_proxy.h" @@ -67,5 +69,86 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) { } } +TEST(PictureLayerTest, ForcedCpuRaster) { + MockContentLayerClient client; + scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client); + + scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); + host->SetRootLayer(layer); + + // The default value is false. + EXPECT_FALSE(layer->ShouldUseGpuRasterization()); + + // Gpu rasterization cannot be enabled even with raster hint. + layer->SetHasGpuRasterizationHint(true); + EXPECT_FALSE(layer->ShouldUseGpuRasterization()); +} + +TEST(PictureLayerTest, ForcedGpuRaster) { + MockContentLayerClient client; + scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client); + + scoped_ptr<FakeLayerTreeHost> host = + FakeLayerTreeHost::Create(GpuRasterizationSettings()); + host->SetRootLayer(layer); + + // The default value is true. + EXPECT_TRUE(layer->ShouldUseGpuRasterization()); + + // Gpu rasterization cannot be disabled even with raster hint. + layer->SetHasGpuRasterizationHint(false); + EXPECT_TRUE(layer->ShouldUseGpuRasterization()); + + // Gpu rasterization cannot be disabled even with skia veto. + PicturePile* pile = layer->GetPicturePileForTesting(); + EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization()); + pile->SetUnsuitableForGpuRasterizationForTesting(); + EXPECT_TRUE(layer->ShouldUseGpuRasterization()); +} + +TEST(PictureLayerTest, HybridRaster) { + MockContentLayerClient client; + scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client); + + scoped_ptr<FakeLayerTreeHost> host = + FakeLayerTreeHost::Create(HybridRasterizationSettings()); + host->SetRootLayer(layer); + + // The default value is false. + EXPECT_FALSE(layer->ShouldUseGpuRasterization()); + + // Gpu rasterization can be enabled first time. + layer->SetHasGpuRasterizationHint(true); + EXPECT_TRUE(layer->ShouldUseGpuRasterization()); + + // Gpu rasterization can always be disabled. + layer->SetHasGpuRasterizationHint(false); + EXPECT_FALSE(layer->ShouldUseGpuRasterization()); + + // Gpu rasterization cannot be enabled once disabled. + layer->SetHasGpuRasterizationHint(true); + EXPECT_FALSE(layer->ShouldUseGpuRasterization()); +} + +TEST(PictureLayerTest, VetoGpuRaster) { + MockContentLayerClient client; + scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client); + + scoped_ptr<FakeLayerTreeHost> host = + FakeLayerTreeHost::Create(HybridRasterizationSettings()); + host->SetRootLayer(layer); + + EXPECT_FALSE(layer->ShouldUseGpuRasterization()); + + layer->SetHasGpuRasterizationHint(true); + EXPECT_TRUE(layer->ShouldUseGpuRasterization()); + + // Veto gpu rasterization. + PicturePile* pile = layer->GetPicturePileForTesting(); + EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization()); + pile->SetUnsuitableForGpuRasterizationForTesting(); + EXPECT_FALSE(layer->ShouldUseGpuRasterization()); +} + } // namespace } // namespace cc diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc index 8080d22c..93b59ae 100644 --- a/cc/resources/picture.cc +++ b/cc/resources/picture.cc @@ -197,6 +197,19 @@ Picture* Picture::GetCloneForDrawingOnThread(unsigned thread_index) { return thread_index == clones_.size() ? this : clones_[thread_index].get(); } +bool Picture::IsSuitableForGpuRasterization() const { + DCHECK(picture_); + + // TODO(alokp): SkPicture::suitableForGpuRasterization needs a GrContext. + // Ideally this GrContext should be the same as that for rasterizing this + // picture. But we are on the main thread while the rasterization context + // may be on the compositor or raster thread. + // SkPicture::suitableForGpuRasterization is not implemented yet. + // Pass a NULL context for now and discuss with skia folks if the context + // is really needed. + return picture_->suitableForGpuRasterization(NULL); +} + void Picture::CloneForDrawing(int num_threads) { TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); diff --git a/cc/resources/picture.h b/cc/resources/picture.h index aef6b95..d32b843 100644 --- a/cc/resources/picture.h +++ b/cc/resources/picture.h @@ -70,6 +70,8 @@ class CC_EXPORT Picture // Has Record() been called yet? bool HasRecording() const { return picture_.get() != NULL; } + bool IsSuitableForGpuRasterization() const; + // Apply this scale and raster the negated region into the canvas. See comment // in PicturePileImpl::RasterCommon for explanation on negated content region. int Raster(SkCanvas* canvas, diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc index 0e2e363..8a15ea6 100644 --- a/cc/resources/picture_pile.cc +++ b/cc/resources/picture_pile.cc @@ -141,8 +141,7 @@ float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, namespace cc { -PicturePile::PicturePile() { -} +PicturePile::PicturePile() : is_suitable_for_gpu_rasterization_(true) {} PicturePile::~PicturePile() { } @@ -245,6 +244,14 @@ bool PicturePile::Update(ContentLayerClient* painter, gather_pixel_refs, num_raster_threads, Picture::RECORD_NORMALLY); + // Note the '&&' with previous is-suitable state. + // This means that once a picture-pile becomes unsuitable for gpu + // rasterization due to some content, it will continue to be unsuitable + // even if that content is replaced by gpu-friendly content. + // This is an optimization to avoid iterating though all pictures in + // the pile after each invalidation. + is_suitable_for_gpu_rasterization_ &= + picture->IsSuitableForGpuRasterization(); base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); best_duration = std::min(duration, best_duration); diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h index 804a679..dbc3966 100644 --- a/cc/resources/picture_pile.h +++ b/cc/resources/picture_pile.h @@ -37,12 +37,21 @@ class CC_EXPORT PicturePile : public PicturePileBase { show_debug_picture_borders_ = show; } + bool is_suitable_for_gpu_rasterization() const { + return is_suitable_for_gpu_rasterization_; + } + void SetUnsuitableForGpuRasterizationForTesting() { + is_suitable_for_gpu_rasterization_ = false; + } + protected: virtual ~PicturePile(); private: friend class PicturePileImpl; + bool is_suitable_for_gpu_rasterization_; + DISALLOW_COPY_AND_ASSIGN(PicturePile); }; |