diff options
-rw-r--r-- | cc/cc.gyp | 2 | ||||
-rw-r--r-- | cc/picture_pile.cc | 7 | ||||
-rw-r--r-- | cc/picture_pile.h | 4 | ||||
-rw-r--r-- | cc/resource_pool.cc | 30 | ||||
-rw-r--r-- | cc/resource_pool.h | 42 | ||||
-rw-r--r-- | cc/test/fake_picture_layer_tiling_client.cc | 2 | ||||
-rw-r--r-- | cc/tile_manager.cc | 194 | ||||
-rw-r--r-- | cc/tile_manager.h | 33 |
8 files changed, 276 insertions, 38 deletions
@@ -159,6 +159,8 @@ 'rendering_stats.h', 'resource.cc', 'resource.h', + 'resource_pool.cc', + 'resource_pool.h', 'resource_provider.cc', 'resource_provider.h', 'resource_update.cc', diff --git a/cc/picture_pile.cc b/cc/picture_pile.cc index 2b947e1..efc471e 100644 --- a/cc/picture_pile.cc +++ b/cc/picture_pile.cc @@ -4,6 +4,7 @@ #include <algorithm> +#include "base/debug/trace_event.h" #include "cc/picture_pile.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -66,7 +67,8 @@ void PicturePile::Update(ContentLayerClient* painter, RenderingStats& stats) { pile_[0]->Record(painter, gfx::Rect(gfx::Point(), size_), stats); } -void PicturePile::CopyAllButPile(PicturePile& from, PicturePile& to) { +void PicturePile::CopyAllButPile( + const PicturePile& from, PicturePile& to) const { to.size_ = from.size_; to.invalidation_ = from.invalidation_; to.prev_invalidation_ = from.prev_invalidation_; @@ -80,7 +82,8 @@ void PicturePile::PushPropertiesTo(PicturePile& other) { other.pile_[i] = pile_[i]; } -scoped_ptr<PicturePile> PicturePile::CloneForDrawing() { +scoped_ptr<PicturePile> PicturePile::CloneForDrawing() const { + TRACE_EVENT0("cc", "PicturePile::CloneForDrawing"); scoped_ptr<PicturePile> clone = make_scoped_ptr(new PicturePile); CopyAllButPile(*this, *clone); diff --git a/cc/picture_pile.h b/cc/picture_pile.h index 13a0b43..0755d7d 100644 --- a/cc/picture_pile.h +++ b/cc/picture_pile.h @@ -36,7 +36,7 @@ public: void PushPropertiesTo(PicturePile& other); // Clone a paint-safe version of this picture (with cloned PicturePileRecords) - scoped_ptr<PicturePile> CloneForDrawing(); + scoped_ptr<PicturePile> CloneForDrawing() const; // Raster a subrect of this PicturePile into the given canvas. // It's only safe to call paint on a cloned version. @@ -44,7 +44,7 @@ public: void Raster(SkCanvas* canvas, gfx::Rect rect); private: - void CopyAllButPile(PicturePile& from, PicturePile& to); + void CopyAllButPile(const PicturePile& from, PicturePile& to) const; std::vector<scoped_refptr<Picture> > pile_; gfx::Size size_; diff --git a/cc/resource_pool.cc b/cc/resource_pool.cc new file mode 100644 index 0000000..24c3755 --- /dev/null +++ b/cc/resource_pool.cc @@ -0,0 +1,30 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/resource_pool.h" + +#include "cc/resource_provider.h" + +namespace cc { + +ResourcePool::ResourcePool(ResourceProvider* resource_provider, + Renderer::ResourcePool pool_id) + : resource_provider_(resource_provider), + pool_id_(pool_id) { +} + +ResourcePool::~ResourcePool() { +} + +ResourceProvider::ResourceId ResourcePool::AcquireResource( + const gfx::Size& size, GLenum format) { + return resource_provider_->createResource( + pool_id_, size, format, ResourceProvider::TextureUsageAny); +} + +void ResourcePool::ReleaseResource(ResourceProvider::ResourceId resource_id) { + resource_provider_->deleteResource(resource_id); +} + +} // namespace cc diff --git a/cc/resource_pool.h b/cc/resource_pool.h new file mode 100644 index 0000000..752d82b --- /dev/null +++ b/cc/resource_pool.h @@ -0,0 +1,42 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_RESOURCE_POOL_H_ +#define CC_RESOURCE_POOL_H_ + +#include "base/memory/scoped_ptr.h" +#include "cc/renderer.h" +#include "cc/resource_provider.h" + +namespace cc { + +class ResourcePool { + public: + static scoped_ptr<ResourcePool> Create(ResourceProvider* resource_provider, + Renderer::ResourcePool pool_id) { + return make_scoped_ptr(new ResourcePool(resource_provider, pool_id)); + } + + virtual ~ResourcePool(); + + ResourceProvider* resource_provider() { return resource_provider_; }; + + ResourceProvider::ResourceId AcquireResource( + const gfx::Size&, GLenum format); + void ReleaseResource(ResourceProvider::ResourceId); + + protected: + ResourcePool(ResourceProvider* resource_provider, + Renderer::ResourcePool pool_id); + + private: + ResourceProvider* resource_provider_; + Renderer::ResourcePool pool_id_; + + DISALLOW_COPY_AND_ASSIGN(ResourcePool); +}; + +} // namespace cc + +#endif // CC_RESOURCE_POOL_H_ diff --git a/cc/test/fake_picture_layer_tiling_client.cc b/cc/test/fake_picture_layer_tiling_client.cc index b3853b6..f608837 100644 --- a/cc/test/fake_picture_layer_tiling_client.cc +++ b/cc/test/fake_picture_layer_tiling_client.cc @@ -7,7 +7,7 @@ namespace cc { FakePictureLayerTilingClient::FakePictureLayerTilingClient() - : tile_manager_(&tile_manager_client_) { + : tile_manager_(&tile_manager_client_, NULL) { } FakePictureLayerTilingClient::~FakePictureLayerTilingClient() { diff --git a/cc/tile_manager.cc b/cc/tile_manager.cc index a1d3b07..58ba68b 100644 --- a/cc/tile_manager.cc +++ b/cc/tile_manager.cc @@ -6,15 +6,62 @@ #include <algorithm> +#include "base/bind.h" +#include "base/debug/trace_event.h" #include "base/logging.h" +#include "base/threading/sequenced_worker_pool.h" +#include "cc/resource_pool.h" #include "cc/tile.h" +#include "third_party/skia/include/core/SkDevice.h" + +namespace { + +void RasterizeTile(cc::PicturePile* picture_pile, + uint8_t* mapped_buffer, + const gfx::Rect& rect) { + TRACE_EVENT0("cc", "RasterizeTile"); + DCHECK(mapped_buffer); + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height()); + bitmap.setPixels(mapped_buffer); + SkDevice device(bitmap); + SkCanvas canvas(&device); + picture_pile->Raster(&canvas, rect); +} + +const int kMaxRasterThreads = 1; + +const char* kRasterThreadNamePrefix = "CompositorRaster"; + +// Allow two pending raster tasks per thread. This keeps resource usage +// low while making sure raster threads aren't unnecessarily idle. +const int kNumPendingRasterTasksPerThread = 2; + +} // namespace namespace cc { -TileManager::TileManager(TileManagerClient* client) - : client_(client) - , manage_tiles_pending_(false) -{ +ManagedTileState::ManagedTileState() + : can_use_gpu_memory(false), + can_be_freed(true), + resource_id(0), + resource_id_is_being_initialized(false) { +} + +ManagedTileState::~ManagedTileState() { + DCHECK(!resource_id); + DCHECK(!resource_id_is_being_initialized); +} + +TileManager::TileManager( + TileManagerClient* client, ResourceProvider* resource_provider) + : client_(client), + resource_pool_(ResourcePool::Create(resource_provider, + Renderer::ImplPool)), + manage_tiles_pending_(false), + pending_raster_tasks_(0), + worker_pool_(new base::SequencedWorkerPool(kMaxRasterThreads, + kRasterThreadNamePrefix)) { } TileManager::~TileManager() { @@ -23,6 +70,10 @@ TileManager::~TileManager() { global_state_ = GlobalStateThatImpactsTilePriority(); ManageTiles(); DCHECK(tiles_.size() == 0); + // This should finish all pending raster tasks and release any + // uninitialized resources. + worker_pool_->Shutdown(); + DCHECK(pending_raster_tasks_ == 0); } void TileManager::SetGlobalState(const GlobalStateThatImpactsTilePriority& global_state) { @@ -38,6 +89,7 @@ void TileManager::RegisterTile(Tile* tile) { void TileManager::UnregisterTile(Tile* tile) { for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); it++) { if (*it == tile) { + FreeResourcesForTile(tile); tiles_.erase(it); return; } @@ -76,6 +128,7 @@ public: }; void TileManager::ManageTiles() { + TRACE_EVENT0("cc", "TileManager::ManageTiles"); // The amount of time for which we want to have prepainting coverage. const double prepainting_window_time_seconds = 1.0; const double backfling_guard_distance_pixels = 314.0; @@ -152,58 +205,151 @@ void TileManager::ManageTiles() { // Sort by bin. std::sort(tiles_.begin(), tiles_.end(), BinComparator()); + // Assign gpu memory and determine what tiles need to be rasterized. + AssignGpuMemoryToTiles(); + + // Finally, kick the rasterizer. + DispatchMoreRasterTasks(); +} + +void TileManager::AssignGpuMemoryToTiles() { + TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles"); // Some memory cannot be released. Figure out which. size_t unreleasable_bytes = 0; for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { Tile* tile = *it; - if (tile->managed_state().resource_id_can_be_freed) + if (!tile->managed_state().can_be_freed) unreleasable_bytes += tile->bytes_consumed_if_allocated(); } // Now give memory out to the tiles until we're out, and build - // the needs-to-be-painted and needs-to-be-freed queues. - tiles_that_need_to_be_painted_.erase( - tiles_that_need_to_be_painted_.begin(), - tiles_that_need_to_be_painted_.end()); + // the needs-to-be-rasterized queue. + tiles_that_need_to_be_rasterized_.erase( + tiles_that_need_to_be_rasterized_.begin(), + tiles_that_need_to_be_rasterized_.end()); size_t bytes_left = global_state_.memory_limit_in_bytes - unreleasable_bytes; for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { Tile* tile = *it; size_t tile_bytes = tile->bytes_consumed_if_allocated(); ManagedTileState& managed_tile_state = tile->managed_state(); - if (managed_tile_state.resource_id_can_be_freed) + if (!managed_tile_state.can_be_freed) continue; if (tile_bytes > bytes_left) { managed_tile_state.can_use_gpu_memory = false; - if (managed_tile_state.resource_id && managed_tile_state.resource_id_can_be_freed) - FreeResourcesForTile(tile); + FreeResourcesForTile(tile); continue; } bytes_left -= tile_bytes; managed_tile_state.can_use_gpu_memory = true; - if (!managed_tile_state.resource_id) - tiles_that_need_to_be_painted_.push_back(tile); + if (!managed_tile_state.resource_id && + !managed_tile_state.resource_id_is_being_initialized) + tiles_that_need_to_be_rasterized_.push_back(tile); } // Reverse two tiles_that_need_* vectors such that pop_back gets // the highest priority tile. std::reverse( - tiles_that_need_to_be_painted_.begin(), - tiles_that_need_to_be_painted_.end()); - - // Finally, kick the rasterizer. - ScheduleMorePaintingJobs(); + tiles_that_need_to_be_rasterized_.begin(), + tiles_that_need_to_be_rasterized_.end()); } void TileManager::FreeResourcesForTile(Tile* tile) { - DCHECK(!tile->managed_state().can_use_gpu_memory && - tile->managed_state().resource_id_can_be_freed); - // TODO(nduca): Do something intelligent here. + ManagedTileState& managed_tile_state = tile->managed_state(); + DCHECK(managed_tile_state.can_be_freed); + if (managed_tile_state.resource_id) { + resource_pool_->ReleaseResource(managed_tile_state.resource_id); + managed_tile_state.resource_id = 0; + } +} + +void TileManager::DispatchMoreRasterTasks() { + while (!tiles_that_need_to_be_rasterized_.empty()) { + int max_pending_tasks = kNumPendingRasterTasksPerThread * + kMaxRasterThreads; + + // Stop dispatching raster tasks when too many are pending. + if (pending_raster_tasks_ >= max_pending_tasks) + break; + + DispatchOneRasterTask(tiles_that_need_to_be_rasterized_.back()); + tiles_that_need_to_be_rasterized_.pop_back(); + } } -void TileManager::ScheduleMorePaintingJobs() { - // TODO(nduca): The next big thing. +void TileManager::DispatchOneRasterTask(scoped_refptr<Tile> tile) { + TRACE_EVENT0("cc", "TileManager::DispatchOneRasterTask"); + scoped_ptr<PicturePile> cloned_picture_pile = + tile->picture_pile()->CloneForDrawing(); + + ManagedTileState& managed_tile_state = tile->managed_state(); + DCHECK(managed_tile_state.can_use_gpu_memory); + ResourceProvider::ResourceId resource_id = + resource_pool_->AcquireResource(tile->tile_size_.size(), tile->format_); + resource_pool_->resource_provider()->acquirePixelBuffer(resource_id); + + managed_tile_state.resource_id_is_being_initialized = true; + managed_tile_state.can_be_freed = false; + + ++pending_raster_tasks_; + worker_pool_->GetTaskRunnerWithShutdownBehavior( + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)->PostTaskAndReply( + FROM_HERE, + base::Bind(&RasterizeTile, + cloned_picture_pile.get(), + resource_pool_->resource_provider()->mapPixelBuffer( + resource_id), + tile->rect_inside_picture_), + base::Bind(&TileManager::OnRasterTaskCompleted, + base::Unretained(this), + tile, + resource_id, + base::Passed(&cloned_picture_pile))); } +void TileManager::OnRasterTaskCompleted( + scoped_refptr<Tile> tile, + ResourceProvider::ResourceId resource_id, + scoped_ptr<PicturePile> cloned_picture_pile) { + TRACE_EVENT0("cc", "TileManager::OnRasterTaskCompleted"); + --pending_raster_tasks_; + + // Release raster resources. + resource_pool_->resource_provider()->unmapPixelBuffer(resource_id); + cloned_picture_pile.reset(); + + ManagedTileState& managed_tile_state = tile->managed_state(); + managed_tile_state.can_be_freed = true; + + // Tile can be freed after the completion of the raster task. Call + // AssignGpuMemoryToTiles() to re-assign gpu memory to highest priority + // tiles. The result of this could be that this tile is no longer + // allowed to use gpu memory and in that case we need to abort + // initialization and free all associated resources before calling + // DispatchMoreRasterTasks(). + AssignGpuMemoryToTiles(); + + // Finish resource initialization if |can_use_gpu_memory| is true. + if (managed_tile_state.can_use_gpu_memory) { + resource_pool_->resource_provider()->setPixelsFromBuffer(resource_id); + resource_pool_->resource_provider()->releasePixelBuffer(resource_id); + + DidFinishTileInitialization(tile, resource_id); + } else { + resource_pool_->resource_provider()->releasePixelBuffer(resource_id); + resource_pool_->ReleaseResource(resource_id); + managed_tile_state.resource_id_is_being_initialized = false; + } + + DispatchMoreRasterTasks(); +} + +void TileManager::DidFinishTileInitialization( + Tile* tile, ResourceProvider::ResourceId resource_id) { + ManagedTileState& managed_tile_state = tile->managed_state(); + DCHECK(!managed_tile_state.resource_id); + managed_tile_state.resource_id = resource_id; + managed_tile_state.resource_id_is_being_initialized = false; +} } diff --git a/cc/tile_manager.h b/cc/tile_manager.h index 47ad63b..f907be9 100644 --- a/cc/tile_manager.h +++ b/cc/tile_manager.h @@ -7,10 +7,16 @@ #include <vector> +#include "base/memory/scoped_ptr.h" #include "base/values.h" #include "cc/layer_tree_host_impl.h" +#include "cc/resource_pool.h" #include "cc/tile_priority.h" +namespace base { +class SequencedWorkerPool; +} + namespace cc { class Tile; @@ -39,15 +45,14 @@ enum TileManagerBin { // managed by the TileManager. class CC_EXPORT ManagedTileState { public: - ManagedTileState() - : can_use_gpu_memory(false) - , resource_id(0) - , resource_id_can_be_freed(0) {} + ManagedTileState(); + ~ManagedTileState(); // Persisted state: valid all the time. bool can_use_gpu_memory; + bool can_be_freed; ResourceProvider::ResourceId resource_id; - bool resource_id_can_be_freed; + bool resource_id_is_being_initialized; // Ephemeral state, valid only during Manage. TileManagerBin bin; @@ -61,8 +66,8 @@ class CC_EXPORT ManagedTileState { // created, and unregister from the manager when they are deleted. class CC_EXPORT TileManager { public: - TileManager(TileManagerClient* client); - ~TileManager(); + TileManager(TileManagerClient* client, ResourceProvider *resource_provider); + virtual ~TileManager(); void SetGlobalState(const GlobalStateThatImpactsTilePriority& state); void ManageTiles(); @@ -75,18 +80,28 @@ class CC_EXPORT TileManager { void WillModifyTilePriority(Tile*, WhichTree, const TilePriority& new_priority); private: + void AssignGpuMemoryToTiles(); void FreeResourcesForTile(Tile*); void ScheduleManageTiles(); - void ScheduleMorePaintingJobs(); + void DispatchMoreRasterTasks(); + void DispatchOneRasterTask(scoped_refptr<Tile>); + void OnRasterTaskCompleted( + scoped_refptr<Tile>, + ResourceProvider::ResourceId, + scoped_ptr<PicturePile>); + void DidFinishTileInitialization(Tile*, ResourceProvider::ResourceId); TileManagerClient* client_; + scoped_ptr<ResourcePool> resource_pool_; bool manage_tiles_pending_; + int pending_raster_tasks_; + scoped_refptr<base::SequencedWorkerPool> worker_pool_; GlobalStateThatImpactsTilePriority global_state_; typedef std::vector<Tile*> TileVector; TileVector tiles_; - TileVector tiles_that_need_to_be_painted_; + TileVector tiles_that_need_to_be_rasterized_; }; } // namespace cc |