Chromium Code Reviews| Index: cc/tile_manager.cc |
| diff --git a/cc/tile_manager.cc b/cc/tile_manager.cc |
| index 80c2c74069c2d06db44d0c03b6c4c04c924b04ae..9b896ea844d5550373a686e4448d467b02b9d02e 100644 |
| --- a/cc/tile_manager.cc |
| +++ b/cc/tile_manager.cc |
| @@ -17,6 +17,7 @@ |
| #include "cc/resource_pool.h" |
| #include "cc/switches.h" |
| #include "cc/tile.h" |
| +#include "skia/ext/lazy_pixel_ref.h" |
| #include "third_party/skia/include/core/SkDevice.h" |
| namespace { |
| @@ -66,6 +67,17 @@ class RasterThread : public base::Thread { |
| base::Bind(&RasterThread::RunReply, base::Unretained(this), reply)); |
| } |
| + void PostImageDecodingTaskAndReply(const tracked_objects::Location& from_here, |
| + SkPixelRef* pixel_ref, |
| + const base::Closure& reply) { |
| + ++num_pending_tasks_; |
| + message_loop_proxy()->PostTaskAndReply( |
| + from_here, |
| + base::Bind(&skia::LazyPixelRef::Decode, base::Unretained( |
| + static_cast<skia::LazyPixelRef*>(pixel_ref))), |
| + base::Bind(&RasterThread::RunReply, base::Unretained(this), reply)); |
| + } |
| + |
| private: |
| static void RunRasterTask(PicturePileImpl* picture_pile, |
| uint8_t* mapped_buffer, |
| @@ -238,6 +250,10 @@ void TileManager::ManageTiles() { |
| } |
| mts.bin = EVENTUALLY_BIN; |
| + |
| + // Update all the SkPixelRefs this tile intersects. |
| + mts.pending_pixel_refs.clear(); |
| + mts.has_image_decoding_info = false; |
| } |
| // Memory limit policy works by mapping some bin states to the NEVER bin. |
| @@ -275,6 +291,17 @@ void TileManager::ManageTiles() { |
| // Assign gpu memory and determine what tiles need to be rasterized. |
| AssignGpuMemoryToTiles(); |
| + // Initialize image information for tiles in the NOW_BIN. For other tiles, |
| + // we will get the information later when decoding is about to start. |
| + for (TileVector::reverse_iterator it = |
| + tiles_that_need_to_be_rasterized_.rbegin(); |
| + it != tiles_that_need_to_be_rasterized_.rend(); ++it) { |
| + if ((*it)->managed_state().bin == NOW_BIN) |
| + GetImageInformationForTile(*it); |
| + else |
| + break; |
| + } |
| + |
| // Finally, kick the rasterizer. |
| DispatchMoreRasterTasks(); |
| } |
| @@ -332,6 +359,15 @@ void TileManager::AssignGpuMemoryToTiles() { |
| tiles_that_need_to_be_rasterized_.end()); |
| } |
| +void TileManager::GetImageInformationForTile(Tile* tile) { |
| + ManagedTileState& managed_state = tile->managed_state(); |
| + if (!managed_state.has_image_decoding_info) { |
| + const_cast<PicturePileImpl *>(tile->picture_pile())->GatherPixelRefs( |
| + tile->rect_inside_picture_, managed_state.pending_pixel_refs); |
| + managed_state.has_image_decoding_info = true; |
| + } |
| +} |
| + |
| void TileManager::FreeResourcesForTile(Tile* tile) { |
| ManagedTileState& managed_tile_state = tile->managed_state(); |
| DCHECK(managed_tile_state.can_be_freed); |
| @@ -339,28 +375,123 @@ void TileManager::FreeResourcesForTile(Tile* tile) { |
| resource_pool_->ReleaseResource(managed_tile_state.resource.Pass()); |
| } |
| +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; |
| +} |
| + |
| void TileManager::DispatchMoreRasterTasks() { |
| while (!tiles_that_need_to_be_rasterized_.empty()) { |
| - 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; |
| - } |
| - |
| + RasterThread* thread = GetFreeRasterThread(); |
| // Stop dispatching tasks when all threads are busy. |
| if (!thread) |
| return; |
| - DispatchOneRasterTask(thread, tiles_that_need_to_be_rasterized_.back()); |
| + Tile* tile = tiles_that_need_to_be_rasterized_.back(); |
| + if (!HasDispatchedImageDecodingTasks(tile)) |
| + DispatchOneRasterTask(thread, tile); |
| tiles_that_need_to_be_rasterized_.pop_back(); |
| } |
| } |
| +bool TileManager::HasDispatchedImageDecodingTasks(Tile* tile) { |
| + bool has_dispatched_task = false; |
| + if (!tile->managed_state().has_image_decoding_info) |
| + GetImageInformationForTile(tile); |
| + |
| + std::vector<int> index_to_be_removed; |
| + RasterThread* thread = 0; |
| + std::vector<SkPixelRef*>& pending_pixel_refs = |
| + tile->managed_state().pending_pixel_refs; |
| + for (int i = 0; i < pending_pixel_refs.size(); ++i) { |
| + SkPixelRef* pixel_ref = pending_pixel_refs[i]; |
| + if (pending_decode_tasks_.end() != pending_decode_tasks_.find( |
| + pixel_ref->getGenerationID())) |
| + continue; |
|
reveman
2012/12/10 17:58:12
I'm confused. Doesn't this function have to return
qinmin
2012/12/10 22:52:51
it should return false in that case, suppose the p
|
| + if (static_cast<skia::LazyPixelRef*>(pixel_ref)->PrepareToDecode( |
| + skia::LazyPixelRef::PrepareParams())) { |
| + index_to_be_removed.push_back(i); |
| + } else { |
| + thread = GetFreeRasterThread(); |
| + if (thread) { |
| + has_dispatched_task = true; |
| + DispatchOneImageDecodingTask(thread, tile, pixel_ref); |
| + } |
| + } |
| + } |
| + |
| + for (std::vector<int>::reverse_iterator it = index_to_be_removed.rbegin(); |
| + it != index_to_be_removed.rend(); ++it) { |
| + pending_pixel_refs.erase(pending_pixel_refs.begin() + (*it)); |
|
reveman
2012/12/10 17:58:12
removing elements from the middle vector is not ve
qinmin
2012/12/10 22:52:51
Switched to list instead
On 2012/12/10 17:58:12,
|
| + } |
| + |
| + if (has_dispatched_task) |
| + tiles_waiting_for_image_decoding_.push_back(tile); |
| + |
| + return has_dispatched_task; |
| +} |
| + |
| +void TileManager::DispatchOneImageDecodingTask(RasterThread* thread, |
| + scoped_refptr<Tile> tile, |
| + SkPixelRef* 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); |
| + |
| + std::vector<int> tile_index_to_be_removed; |
| + for (int i = 0; i < tiles_waiting_for_image_decoding_.size(); ++i) { |
| + std::vector<SkPixelRef*>& pixel_refs = |
| + tiles_waiting_for_image_decoding_[i]-> |
| + managed_state().pending_pixel_refs; |
| + for (std::vector<SkPixelRef*>::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); |
| + tile_index_to_be_removed.push_back(i); |
| + break; |
| + } |
| + } |
| + } |
| + |
| + // Tiles are in increasing priority in the image decoding queue. But since |
| + // we are appending tiles to the back of the rasterize queue, we need to |
| + // iterate through tiles reversely. |
| + for (std::vector<int>::reverse_iterator it = |
| + tile_index_to_be_removed.rbegin(); |
| + it != tile_index_to_be_removed.rend(); ++it) { |
| + tiles_that_need_to_be_rasterized_.push_back( |
| + tiles_waiting_for_image_decoding_[*it]); |
| + tiles_waiting_for_image_decoding_.erase( |
| + tiles_waiting_for_image_decoding_.begin() + (*it)); |
|
reveman
2012/12/10 17:58:12
again removing elements from the middle of vector.
qinmin
2012/12/10 22:52:51
using list instead
On 2012/12/10 17:58:12, David
|
| + } |
| + |
| + DispatchMoreRasterTasks(); |
| +} |
| + |
| void TileManager::DispatchOneRasterTask( |
| RasterThread* thread, scoped_refptr<Tile> tile) { |
| TRACE_EVENT0("cc", "TileManager::DispatchOneRasterTask"); |