0

Implement the logic to kick off image decoding jobs for TileManager

BUG=163980


Review URL: https://chromiumcodereview.appspot.com/11453014

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@172813 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
qinmin@chromium.org
2012-12-13 04:28:05 +00:00
parent 73aecc2142
commit f760de8e8a
7 changed files with 223 additions and 25 deletions

@ -7,8 +7,15 @@
#include "cc/picture.h"
#include "cc/rendering_stats.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/utils/SkPictureUtils.h"
#include "ui/gfx/rect_conversions.h"
namespace {
// URI label for a lazily decoded SkPixelRef.
const char labelLazyDecoded[] = "lazy";
}
namespace cc {
scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) {
@ -89,4 +96,32 @@ void Picture::Raster(SkCanvas* canvas) {
canvas->restore();
}
void Picture::GatherPixelRefs(const gfx::Rect& rect,
std::list<skia::LazyPixelRef*>& result) {
DCHECK(picture_);
SkData* pixel_refs = SkPictureUtils::GatherPixelRefs(
picture_.get(), SkRect::MakeXYWH(rect.x(),
rect.y(),
rect.width(),
rect.height()));
if (!pixel_refs)
return;
void* data = const_cast<void*>(pixel_refs->data());
if (!data) {
pixel_refs->unref();
return;
}
SkPixelRef** refs = reinterpret_cast<SkPixelRef**>(data);
for (unsigned int i = 0; i < pixel_refs->size() / sizeof(SkPixelRef*); ++i) {
if (*refs && (*refs)->getURI() && !strncmp(
(*refs)->getURI(), labelLazyDecoded, 4)) {
result.push_back(static_cast<skia::LazyPixelRef*>(*refs));
}
refs++;
}
pixel_refs->unref();
}
} // namespace cc

@ -5,11 +5,15 @@
#ifndef CC_PICTURE_H_
#define CC_PICTURE_H_
#include <list>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "cc/cc_export.h"
#include "skia/ext/lazy_pixel_ref.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkPixelRef.h"
#include "ui/gfx/rect.h"
namespace cc {
@ -39,6 +43,9 @@ public:
// Assumes contentsScale have already been applied.
void Raster(SkCanvas* canvas);
void GatherPixelRefs(const gfx::Rect& rect,
std::list<skia::LazyPixelRef*>&);
private:
Picture(gfx::Rect layer_rect);
// This constructor assumes SkPicture is already ref'd and transfers

@ -79,4 +79,14 @@ void PicturePileImpl::Raster(
rasterizeBeginTime).InSecondsF();
}
void PicturePileImpl::GatherPixelRefs(
const gfx::Rect& rect, std::list<skia::LazyPixelRef*>& pixel_refs) {
std::list<skia::LazyPixelRef*> result;
for (PicturePile::Pile::const_iterator i = pile_.begin();
i != pile_.end(); ++i) {
(*i)->GatherPixelRefs(rect, result);
pixel_refs.splice(pixel_refs.end(), result);
}
}
} // namespace cc

@ -5,6 +5,7 @@
#ifndef CC_PICTURE_PILE_IMPL_H_
#define CC_PICTURE_PILE_IMPL_H_
#include <list>
#include <map>
#include "base/basictypes.h"
@ -38,6 +39,8 @@ public:
float contents_scale,
RenderingStats* stats);
void GatherPixelRefs(const gfx::Rect&, std::list<skia::LazyPixelRef*>&);
private:
friend class PicturePile;

@ -5,6 +5,7 @@
#include "cc/tile_manager.h"
#include <algorithm>
#include <set>
#include "base/bind.h"
#include "base/command_line.h"
@ -66,6 +67,16 @@ class RasterThread : public base::Thread {
base::Bind(&RasterThread::RunReply, base::Unretained(this), reply));
}
void PostImageDecodingTaskAndReply(const tracked_objects::Location& from_here,
skia::LazyPixelRef* pixel_ref,
const base::Closure& reply) {
++num_pending_tasks_;
message_loop_proxy()->PostTaskAndReply(
from_here,
base::Bind(&RunImageDecodeTask, base::Unretained(pixel_ref)),
base::Bind(&RasterThread::RunReply, base::Unretained(this), reply));
}
private:
static void RunRasterTask(PicturePileImpl* picture_pile,
uint8_t* mapped_buffer,
@ -87,6 +98,11 @@ class RasterThread : public base::Thread {
stats);
}
static void RunImageDecodeTask(skia::LazyPixelRef* pixel_ref) {
TRACE_EVENT0("cc", "RasterThread::RunImageDecodeTask");
pixel_ref->Decode();
}
void RunReply(const base::Closure& reply) {
--num_pending_tasks_;
reply.Run();
@ -101,7 +117,8 @@ ManagedTileState::ManagedTileState()
: can_use_gpu_memory(false),
can_be_freed(true),
resource_is_being_initialized(false),
contents_swizzled(false) {
contents_swizzled(false),
need_to_gather_pixel_refs(true) {
}
ManagedTileState::~ManagedTileState() {
@ -284,7 +301,7 @@ void TileManager::ManageTiles() {
AssignGpuMemoryToTiles();
// Finally, kick the rasterizer.
DispatchMoreRasterTasks();
DispatchMoreTasks();
}
void TileManager::CheckForCompletedSetPixels() {
@ -332,6 +349,15 @@ void TileManager::AssignGpuMemoryToTiles() {
tiles_that_need_to_be_rasterized_.begin(),
tiles_that_need_to_be_rasterized_.end());
// Record all the tiles in the image decoding list. A tile will not be
// inserted to the rasterizer queue if it is waiting for image decoding.
std::set<Tile*> image_decoding_tile_set;
for (std::list<Tile*>::iterator it = tiles_with_image_decoding_tasks_.begin();
it != tiles_with_image_decoding_tasks_.end(); ++it) {
image_decoding_tile_set.insert(*it);
}
tiles_with_image_decoding_tasks_.clear();
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;
@ -352,8 +378,12 @@ void TileManager::AssignGpuMemoryToTiles() {
bytes_left -= tile_bytes;
managed_tile_state.can_use_gpu_memory = true;
if (!managed_tile_state.resource &&
!managed_tile_state.resource_is_being_initialized)
tiles_that_need_to_be_rasterized_.push_back(tile);
!managed_tile_state.resource_is_being_initialized) {
if (image_decoding_tile_set.end() != image_decoding_tile_set.find(tile))
tiles_with_image_decoding_tasks_.push_back(tile);
else
tiles_that_need_to_be_rasterized_.push_back(tile);
}
}
// Reverse two tiles_that_need_* vectors such that pop_back gets
@ -370,28 +400,125 @@ void TileManager::FreeResourcesForTile(Tile* tile) {
resource_pool_->ReleaseResource(managed_tile_state.resource.Pass());
}
void TileManager::DispatchMoreRasterTasks() {
while (!tiles_that_need_to_be_rasterized_.empty()) {
RasterThread* thread = 0;
RasterThread* TileManager::GetFreeRasterThread() {
RasterThread* thread = 0;
for (RasterThreadVector::iterator it = raster_threads_.begin();
it != raster_threads_.end(); ++it) {
if ((*it)->num_pending_tasks() == kNumPendingRasterTasksPerThread)
continue;
// Check if this is the best thread we've found so far.
if (!thread || (*it)->num_pending_tasks() < thread->num_pending_tasks())
thread = *it;
}
return thread;
}
for (RasterThreadVector::iterator it = raster_threads_.begin();
it != raster_threads_.end(); ++it) {
if ((*it)->num_pending_tasks() == kNumPendingRasterTasksPerThread)
continue;
// Check if this is the best thread we've found so far.
if (!thread || (*it)->num_pending_tasks() < thread->num_pending_tasks())
thread = *it;
}
// Stop dispatching tasks when all threads are busy.
if (!thread)
void TileManager::DispatchMoreTasks() {
// Because tiles in the image decoding list have higher priorities, we
// need to process those tiles first before we start to handle the tiles
// in the need_to_be_rasterized queue.
std::list<Tile*>::iterator it = tiles_with_image_decoding_tasks_.begin();
while (it != tiles_with_image_decoding_tasks_.end()) {
DispatchImageDecodingTasksForTile(*it);
ManagedTileState& managed_state = (*it)->managed_state();
if (managed_state.pending_pixel_refs.empty()) {
RasterThread* thread = GetFreeRasterThread();
if (!thread)
return;
DispatchOneRasterTask(thread, *it);
tiles_with_image_decoding_tasks_.erase(it++);
} else {
++it;
}
}
DispatchOneRasterTask(thread, tiles_that_need_to_be_rasterized_.back());
// Process all tiles in the need_to_be_rasterized queue. If a tile has
// image decoding tasks, put it to the back of the image decoding list.
while (!tiles_that_need_to_be_rasterized_.empty()) {
Tile* tile = tiles_that_need_to_be_rasterized_.back();
DispatchImageDecodingTasksForTile(tile);
ManagedTileState& managed_state = tile->managed_state();
if (!managed_state.pending_pixel_refs.empty()) {
tiles_with_image_decoding_tasks_.push_back(tile);
} else {
RasterThread* thread = GetFreeRasterThread();
if (!thread)
return;
DispatchOneRasterTask(thread, tile);
}
tiles_that_need_to_be_rasterized_.pop_back();
}
}
void TileManager::DispatchImageDecodingTasksForTile(Tile* tile) {
ManagedTileState& managed_state = tile->managed_state();
if (managed_state.need_to_gather_pixel_refs) {
TRACE_EVENT0("cc",
"TileManager::DispatchImageDecodingTaskForTile: Gather PixelRefs");
const_cast<PicturePileImpl *>(tile->picture_pile())->GatherPixelRefs(
tile->content_rect_, managed_state.pending_pixel_refs);
managed_state.need_to_gather_pixel_refs = false;
}
std::list<skia::LazyPixelRef*>& pending_pixel_refs =
tile->managed_state().pending_pixel_refs;
std::list<skia::LazyPixelRef*>::iterator it = pending_pixel_refs.begin();
while (it != pending_pixel_refs.end()) {
if (pending_decode_tasks_.end() != pending_decode_tasks_.find(
(*it)->getGenerationID())) {
++it;
continue;
}
// TODO(qinmin): passing correct image size to PrepareToDecode().
if ((*it)->PrepareToDecode(skia::LazyPixelRef::PrepareParams())) {
pending_pixel_refs.erase(it++);
} else {
RasterThread* thread = GetFreeRasterThread();
if (thread)
DispatchOneImageDecodingTask(thread, tile, *it);
++it;
}
}
}
void TileManager::DispatchOneImageDecodingTask(RasterThread* thread,
scoped_refptr<Tile> tile,
skia::LazyPixelRef* pixel_ref) {
TRACE_EVENT0("cc", "TileManager::DispatchOneImageDecodingTask");
uint32_t pixel_ref_id = pixel_ref->getGenerationID();
DCHECK(pending_decode_tasks_.end() ==
pending_decode_tasks_.find(pixel_ref_id));
pending_decode_tasks_[pixel_ref_id] = pixel_ref;
thread->PostImageDecodingTaskAndReply(
FROM_HERE,
pixel_ref,
base::Bind(&TileManager::OnImageDecodingTaskCompleted,
base::Unretained(this),
tile,
pixel_ref_id));
}
void TileManager::OnImageDecodingTaskCompleted(scoped_refptr<Tile> tile,
uint32_t pixel_ref_id) {
TRACE_EVENT0("cc", "TileManager::OnImageDecoded");
pending_decode_tasks_.erase(pixel_ref_id);
for (TileList::iterator it = tiles_with_image_decoding_tasks_.begin();
it != tiles_with_image_decoding_tasks_.end(); ++it) {
std::list<skia::LazyPixelRef*>& pixel_refs =
(*it)->managed_state().pending_pixel_refs;
for (std::list<skia::LazyPixelRef*>::iterator pixel_it =
pixel_refs.begin(); pixel_it != pixel_refs.end(); ++pixel_it) {
if (pixel_ref_id == (*pixel_it)->getGenerationID()) {
pixel_refs.erase(pixel_it);
break;
}
}
}
DispatchMoreTasks();
}
void TileManager::DispatchOneRasterTask(
RasterThread* thread, scoped_refptr<Tile> tile) {
TRACE_EVENT0("cc", "TileManager::DispatchOneRasterTask");
@ -446,7 +573,7 @@ void TileManager::OnRasterTaskCompleted(
// 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().
// DispatchMoreTasks().
AssignGpuMemoryToTiles();
// Finish resource initialization if |can_use_gpu_memory| is true.
@ -470,8 +597,7 @@ void TileManager::OnRasterTaskCompleted(
resource_pool_->ReleaseResource(resource.Pass());
managed_tile_state.resource_is_being_initialized = false;
}
DispatchMoreRasterTasks();
DispatchMoreTasks();
}
void TileManager::DidFinishTileInitialization(Tile* tile) {

@ -5,9 +5,11 @@
#ifndef CC_TILE_MANAGER_H_
#define CC_TILE_MANAGER_H_
#include <list>
#include <queue>
#include <vector>
#include "base/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "cc/resource_pool.h"
@ -53,6 +55,8 @@ class CC_EXPORT ManagedTileState {
scoped_ptr<ResourcePool::Resource> resource;
bool resource_is_being_initialized;
bool contents_swizzled;
bool need_to_gather_pixel_refs;
std::list<skia::LazyPixelRef*> pending_pixel_refs;
// Ephemeral state, valid only during Manage.
TileManagerBin bin;
@ -91,7 +95,7 @@ class CC_EXPORT TileManager {
void FreeResourcesForTile(Tile*);
void ScheduleManageTiles();
void ScheduleCheckForCompletedSetPixels();
void DispatchMoreRasterTasks();
void DispatchMoreTasks();
void DispatchOneRasterTask(RasterThread*, scoped_refptr<Tile>);
void OnRasterTaskCompleted(
scoped_refptr<Tile>,
@ -99,6 +103,11 @@ class CC_EXPORT TileManager {
scoped_refptr<PicturePileImpl>,
RenderingStats*);
void DidFinishTileInitialization(Tile*);
void DispatchImageDecodingTasksForTile(Tile*);
void OnImageDecodingTaskCompleted(scoped_refptr<Tile>, uint32_t);
void DispatchOneImageDecodingTask(
RasterThread*, scoped_refptr<Tile>, skia::LazyPixelRef*);
RasterThread* GetFreeRasterThread();
TileManagerClient* client_;
scoped_ptr<ResourcePool> resource_pool_;
@ -111,6 +120,14 @@ class CC_EXPORT TileManager {
TileVector tiles_;
TileVector tiles_that_need_to_be_rasterized_;
typedef std::list<Tile*> TileList;
// Tiles with image decoding tasks. These tiles need to be rasterized
// when all the image decoding tasks finish.
TileList tiles_with_image_decoding_tasks_;
typedef base::hash_map<uint32_t, skia::LazyPixelRef*> PixelRefMap;
PixelRefMap pending_decode_tasks_;
typedef std::queue<scoped_refptr<Tile> > TileQueue;
TileQueue tiles_with_pending_set_pixels_;

@ -136,7 +136,7 @@
'../third_party/skia/src/utils/SkNullCanvas.cpp',
'../third_party/skia/include/utils/SkNWayCanvas.h',
'../third_party/skia/src/utils/SkNWayCanvas.cpp',
'../third_party/skia/src/utils/SkPictureUtils.cpp',
'../third_party/skia/include/pdf/SkPDFDevice.h',
'../third_party/skia/include/pdf/SkPDFDocument.h',
@ -151,7 +151,7 @@
'../third_party/skia/include/images/SkPageFlipper.h',
'../third_party/skia/include/utils/SkNullCanvas.h',
'../third_party/skia/include/utils/SkPictureUtils.h',
'ext/bitmap_platform_device.h',
'ext/bitmap_platform_device_android.cc',
'ext/bitmap_platform_device_android.h',