summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cc/cc.gyp2
-rw-r--r--cc/picture_pile.cc7
-rw-r--r--cc/picture_pile.h4
-rw-r--r--cc/resource_pool.cc30
-rw-r--r--cc/resource_pool.h42
-rw-r--r--cc/test/fake_picture_layer_tiling_client.cc2
-rw-r--r--cc/tile_manager.cc194
-rw-r--r--cc/tile_manager.h33
8 files changed, 276 insertions, 38 deletions
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 58ebc04..d2f878a 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -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