| Index: cc/tile_manager.cc
|
| diff --git a/cc/tile_manager.cc b/cc/tile_manager.cc
|
| deleted file mode 100644
|
| index b7bd9dc5463dada49669e32b10ef54d1a6ae0c80..0000000000000000000000000000000000000000
|
| --- a/cc/tile_manager.cc
|
| +++ /dev/null
|
| @@ -1,1114 +0,0 @@
|
| -// 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/tile_manager.h"
|
| -
|
| -#include <algorithm>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/debug/trace_event.h"
|
| -#include "base/json/json_writer.h"
|
| -#include "base/logging.h"
|
| -#include "base/metrics/histogram.h"
|
| -#include "cc/debug/devtools_instrumentation.h"
|
| -#include "cc/platform_color.h"
|
| -#include "cc/raster_worker_pool.h"
|
| -#include "cc/resource_pool.h"
|
| -#include "cc/tile.h"
|
| -#include "third_party/skia/include/core/SkDevice.h"
|
| -
|
| -namespace cc {
|
| -
|
| -namespace {
|
| -
|
| -// If we raster too fast we become upload bound, and pending
|
| -// uploads consume memory. For maximum upload throughput, we would
|
| -// want to allow for upload_throughput * pipeline_time of pending
|
| -// uploads, after which we are just wasting memory. Since we don't
|
| -// know our upload throughput yet, this just caps our memory usage.
|
| -#if defined(OS_ANDROID)
|
| -// For reference, the Nexus10 can upload 1MB in about 2.5ms.
|
| -// Assuming a three frame deep pipeline this implies ~20MB.
|
| -const int kMaxPendingUploadBytes = 20 * 1024 * 1024;
|
| -// TODO(epenner): We should remove this upload limit (crbug.com/176197)
|
| -const int kMaxPendingUploads = 72;
|
| -#else
|
| -const int kMaxPendingUploadBytes = 100 * 1024 * 1024;
|
| -const int kMaxPendingUploads = 1000;
|
| -#endif
|
| -
|
| -#if defined(OS_ANDROID)
|
| -const int kMaxNumPendingTasksPerThread = 8;
|
| -#else
|
| -const int kMaxNumPendingTasksPerThread = 40;
|
| -#endif
|
| -
|
| -// Limit for time spent running cheap tasks during a single frame.
|
| -// TODO(skyostil): Determine this limit more dynamically.
|
| -const int kRunCheapTasksTimeMs = 6;
|
| -
|
| -// Determine bin based on three categories of tiles: things we need now,
|
| -// things we need soon, and eventually.
|
| -inline TileManagerBin BinFromTilePriority(const TilePriority& prio) {
|
| - if (!prio.is_live)
|
| - return NEVER_BIN;
|
| -
|
| - // The amount of time for which we want to have prepainting coverage.
|
| - const float kPrepaintingWindowTimeSeconds = 1.0f;
|
| - const float kBackflingGuardDistancePixels = 314.0f;
|
| -
|
| - // Explicitly limit how far ahead we will prepaint to limit memory usage.
|
| - if (prio.distance_to_visible_in_pixels >
|
| - TilePriority::kMaxDistanceInContentSpace)
|
| - return NEVER_BIN;
|
| -
|
| - if (prio.time_to_visible_in_seconds == 0 ||
|
| - prio.distance_to_visible_in_pixels < kBackflingGuardDistancePixels)
|
| - return NOW_BIN;
|
| -
|
| - if (prio.resolution == NON_IDEAL_RESOLUTION)
|
| - return EVENTUALLY_BIN;
|
| -
|
| - if (prio.time_to_visible_in_seconds < kPrepaintingWindowTimeSeconds)
|
| - return SOON_BIN;
|
| -
|
| - return EVENTUALLY_BIN;
|
| -}
|
| -
|
| -std::string ValueToString(scoped_ptr<base::Value> value)
|
| -{
|
| - std::string str;
|
| - base::JSONWriter::Write(value.get(), &str);
|
| - return str;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -scoped_ptr<base::Value> TileManagerBinAsValue(TileManagerBin bin) {
|
| - switch (bin) {
|
| - case NOW_BIN:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "NOW_BIN"));
|
| - case SOON_BIN:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "SOON_BIN"));
|
| - case EVENTUALLY_BIN:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "EVENTUALLY_BIN"));
|
| - case NEVER_BIN:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "NEVER_BIN"));
|
| - default:
|
| - DCHECK(false) << "Unrecognized TileManagerBin value " << bin;
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "<unknown TileManagerBin value>"));
|
| - }
|
| -}
|
| -
|
| -scoped_ptr<base::Value> TileManagerBinPriorityAsValue(
|
| - TileManagerBinPriority bin_priority) {
|
| - switch (bin_priority) {
|
| - case HIGH_PRIORITY_BIN:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "HIGH_PRIORITY_BIN"));
|
| - case LOW_PRIORITY_BIN:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "LOW_PRIORITY_BIN"));
|
| - default:
|
| - DCHECK(false) << "Unrecognized TileManagerBinPriority value";
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "<unknown TileManagerBinPriority value>"));
|
| - }
|
| -}
|
| -
|
| -scoped_ptr<base::Value> TileRasterStateAsValue(
|
| - TileRasterState raster_state) {
|
| - switch (raster_state) {
|
| - case IDLE_STATE:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "IDLE_STATE"));
|
| - case WAITING_FOR_RASTER_STATE:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "WAITING_FOR_RASTER_STATE"));
|
| - case RASTER_STATE:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "RASTER_STATE"));
|
| - case UPLOAD_STATE:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "UPLOAD_STATE"));
|
| - case FORCED_UPLOAD_COMPLETION_STATE:
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "FORCED_UPLOAD_COMPLETION_STATE"));
|
| - default:
|
| - DCHECK(false) << "Unrecognized TileRasterState value";
|
| - return scoped_ptr<base::Value>(base::Value::CreateStringValue(
|
| - "<unknown TileRasterState value>"));
|
| - }
|
| -}
|
| -
|
| -TileManager::TileManager(
|
| - TileManagerClient* client,
|
| - ResourceProvider* resource_provider,
|
| - size_t num_raster_threads,
|
| - bool use_cheapness_estimator,
|
| - bool use_color_estimator,
|
| - bool prediction_benchmarking)
|
| - : client_(client),
|
| - resource_pool_(ResourcePool::Create(resource_provider)),
|
| - raster_worker_pool_(RasterWorkerPool::Create(this, num_raster_threads)),
|
| - manage_tiles_pending_(false),
|
| - manage_tiles_call_count_(0),
|
| - bytes_pending_upload_(0),
|
| - has_performed_uploads_since_last_flush_(false),
|
| - ever_exceeded_memory_budget_(false),
|
| - record_rendering_stats_(false),
|
| - use_cheapness_estimator_(use_cheapness_estimator),
|
| - use_color_estimator_(use_color_estimator),
|
| - did_schedule_cheap_tasks_(false),
|
| - allow_cheap_tasks_(true),
|
| - prediction_benchmarking_(prediction_benchmarking),
|
| - pending_tasks_(0),
|
| - max_pending_tasks_(kMaxNumPendingTasksPerThread * num_raster_threads) {
|
| - for (int i = 0; i < NUM_STATES; ++i) {
|
| - for (int j = 0; j < NUM_TREES; ++j) {
|
| - for (int k = 0; k < NUM_BINS; ++k)
|
| - raster_state_count_[i][j][k] = 0;
|
| - }
|
| - }
|
| -}
|
| -
|
| -TileManager::~TileManager() {
|
| - // Reset global state and manage. This should cause
|
| - // our memory usage to drop to zero.
|
| - global_state_ = GlobalStateThatImpactsTilePriority();
|
| - AssignGpuMemoryToTiles();
|
| - // This should finish all pending tasks and release any uninitialized
|
| - // resources.
|
| - raster_worker_pool_.reset();
|
| - AbortPendingTileUploads();
|
| - DCHECK_EQ(tiles_with_pending_upload_.size(), 0);
|
| - DCHECK_EQ(all_tiles_.size(), 0);
|
| - DCHECK_EQ(live_or_allocated_tiles_.size(), 0);
|
| -}
|
| -
|
| -void TileManager::SetGlobalState(
|
| - const GlobalStateThatImpactsTilePriority& global_state) {
|
| - global_state_ = global_state;
|
| - resource_pool_->SetMaxMemoryUsageBytes(global_state_.memory_limit_in_bytes);
|
| - ScheduleManageTiles();
|
| -}
|
| -
|
| -void TileManager::RegisterTile(Tile* tile) {
|
| - all_tiles_.insert(tile);
|
| -
|
| - const ManagedTileState& mts = tile->managed_state();
|
| - for (int i = 0; i < NUM_TREES; ++i)
|
| - ++raster_state_count_[mts.raster_state][i][mts.tree_bin[i]];
|
| -
|
| - ScheduleManageTiles();
|
| -}
|
| -
|
| -void TileManager::UnregisterTile(Tile* tile) {
|
| - for (TileList::iterator it = tiles_with_image_decoding_tasks_.begin();
|
| - it != tiles_with_image_decoding_tasks_.end(); it++) {
|
| - if (*it == tile) {
|
| - tiles_with_image_decoding_tasks_.erase(it);
|
| - break;
|
| - }
|
| - }
|
| - for (TileVector::iterator it = tiles_that_need_to_be_rasterized_.begin();
|
| - it != tiles_that_need_to_be_rasterized_.end(); it++) {
|
| - if (*it == tile) {
|
| - tiles_that_need_to_be_rasterized_.erase(it);
|
| - break;
|
| - }
|
| - }
|
| - for (TileVector::iterator it = live_or_allocated_tiles_.begin();
|
| - it != live_or_allocated_tiles_.end(); it++) {
|
| - if (*it == tile) {
|
| - live_or_allocated_tiles_.erase(it);
|
| - break;
|
| - }
|
| - }
|
| - TileSet::iterator it = all_tiles_.find(tile);
|
| - DCHECK(it != all_tiles_.end());
|
| - const ManagedTileState& mts = tile->managed_state();
|
| - for (int i = 0; i < NUM_TREES; ++i)
|
| - --raster_state_count_[mts.raster_state][i][mts.tree_bin[i]];
|
| - FreeResourcesForTile(tile);
|
| - all_tiles_.erase(it);
|
| -}
|
| -
|
| -class BinComparator {
|
| -public:
|
| - bool operator() (const Tile* a, const Tile* b) const {
|
| - const ManagedTileState& ams = a->managed_state();
|
| - const ManagedTileState& bms = b->managed_state();
|
| - if (ams.bin[HIGH_PRIORITY_BIN] != bms.bin[HIGH_PRIORITY_BIN])
|
| - return ams.bin[HIGH_PRIORITY_BIN] < bms.bin[HIGH_PRIORITY_BIN];
|
| -
|
| - if (ams.bin[LOW_PRIORITY_BIN] != bms.bin[LOW_PRIORITY_BIN])
|
| - return ams.bin[LOW_PRIORITY_BIN] < bms.bin[LOW_PRIORITY_BIN];
|
| -
|
| - if (ams.resolution != bms.resolution)
|
| - return ams.resolution < bms.resolution;
|
| -
|
| - if (ams.time_to_needed_in_seconds != bms.time_to_needed_in_seconds)
|
| - return ams.time_to_needed_in_seconds < bms.time_to_needed_in_seconds;
|
| -
|
| - if (ams.distance_to_visible_in_pixels != bms.distance_to_visible_in_pixels)
|
| - return ams.distance_to_visible_in_pixels < bms.distance_to_visible_in_pixels;
|
| -
|
| - gfx::Rect a_rect = a->content_rect();
|
| - gfx::Rect b_rect = b->content_rect();
|
| - if (a_rect.y() != b_rect.y())
|
| - return a_rect.y() < b_rect.y();
|
| - return a_rect.x() < b_rect.x();
|
| - }
|
| -};
|
| -
|
| -void TileManager::SortTiles() {
|
| - TRACE_EVENT0("cc", "TileManager::SortTiles");
|
| - TRACE_COUNTER_ID1("cc", "LiveTileCount", this, live_or_allocated_tiles_.size());
|
| -
|
| - // Sort by bin, resolution and time until needed.
|
| - std::sort(live_or_allocated_tiles_.begin(),
|
| - live_or_allocated_tiles_.end(), BinComparator());
|
| -}
|
| -
|
| -void TileManager::ManageTiles() {
|
| - TRACE_EVENT0("cc", "TileManager::ManageTiles");
|
| - manage_tiles_pending_ = false;
|
| - ++manage_tiles_call_count_;
|
| -
|
| - const TreePriority tree_priority = global_state_.tree_priority;
|
| - TRACE_COUNTER_ID1("cc", "TileCount", this, all_tiles_.size());
|
| -
|
| - // Memory limit policy works by mapping some bin states to the NEVER bin.
|
| - TileManagerBin bin_map[NUM_BINS];
|
| - if (global_state_.memory_limit_policy == ALLOW_NOTHING) {
|
| - bin_map[NOW_BIN] = NEVER_BIN;
|
| - bin_map[SOON_BIN] = NEVER_BIN;
|
| - bin_map[EVENTUALLY_BIN] = NEVER_BIN;
|
| - bin_map[NEVER_BIN] = NEVER_BIN;
|
| - } else if (global_state_.memory_limit_policy == ALLOW_ABSOLUTE_MINIMUM) {
|
| - bin_map[NOW_BIN] = NOW_BIN;
|
| - bin_map[SOON_BIN] = NEVER_BIN;
|
| - bin_map[EVENTUALLY_BIN] = NEVER_BIN;
|
| - bin_map[NEVER_BIN] = NEVER_BIN;
|
| - } else if (global_state_.memory_limit_policy == ALLOW_PREPAINT_ONLY) {
|
| - bin_map[NOW_BIN] = NOW_BIN;
|
| - bin_map[SOON_BIN] = SOON_BIN;
|
| - bin_map[EVENTUALLY_BIN] = NEVER_BIN;
|
| - bin_map[NEVER_BIN] = NEVER_BIN;
|
| - } else {
|
| - bin_map[NOW_BIN] = NOW_BIN;
|
| - bin_map[SOON_BIN] = SOON_BIN;
|
| - bin_map[EVENTUALLY_BIN] = EVENTUALLY_BIN;
|
| - bin_map[NEVER_BIN] = NEVER_BIN;
|
| - }
|
| -
|
| - live_or_allocated_tiles_.clear();
|
| - // For each tree, bin into different categories of tiles.
|
| - for (TileSet::iterator it = all_tiles_.begin();
|
| - it != all_tiles_.end(); ++it) {
|
| - Tile* tile = *it;
|
| - ManagedTileState& mts = tile->managed_state();
|
| -
|
| - TilePriority prio[NUM_BIN_PRIORITIES];
|
| - switch (tree_priority) {
|
| - case SAME_PRIORITY_FOR_BOTH_TREES:
|
| - prio[HIGH_PRIORITY_BIN] = prio[LOW_PRIORITY_BIN] =
|
| - tile->combined_priority();
|
| - break;
|
| - case SMOOTHNESS_TAKES_PRIORITY:
|
| - prio[HIGH_PRIORITY_BIN] = tile->priority(ACTIVE_TREE);
|
| - prio[LOW_PRIORITY_BIN] = tile->priority(PENDING_TREE);
|
| - break;
|
| - case NEW_CONTENT_TAKES_PRIORITY:
|
| - prio[HIGH_PRIORITY_BIN] = tile->priority(PENDING_TREE);
|
| - prio[LOW_PRIORITY_BIN] = tile->priority(ACTIVE_TREE);
|
| - break;
|
| - }
|
| -
|
| - mts.resolution = prio[HIGH_PRIORITY_BIN].resolution;
|
| - mts.time_to_needed_in_seconds =
|
| - prio[HIGH_PRIORITY_BIN].time_to_visible_in_seconds;
|
| - mts.distance_to_visible_in_pixels =
|
| - prio[HIGH_PRIORITY_BIN].distance_to_visible_in_pixels;
|
| - mts.bin[HIGH_PRIORITY_BIN] = BinFromTilePriority(prio[HIGH_PRIORITY_BIN]);
|
| - mts.bin[LOW_PRIORITY_BIN] = BinFromTilePriority(prio[LOW_PRIORITY_BIN]);
|
| - mts.gpu_memmgr_stats_bin = BinFromTilePriority(tile->combined_priority());
|
| -
|
| - DidTileTreeBinChange(tile,
|
| - bin_map[BinFromTilePriority(tile->priority(ACTIVE_TREE))],
|
| - ACTIVE_TREE);
|
| - DidTileTreeBinChange(tile,
|
| - bin_map[BinFromTilePriority(tile->priority(PENDING_TREE))],
|
| - PENDING_TREE);
|
| -
|
| - for (int i = 0; i < NUM_BIN_PRIORITIES; ++i)
|
| - mts.bin[i] = bin_map[mts.bin[i]];
|
| -
|
| - if (!mts.drawing_info.resource_ &&
|
| - !mts.drawing_info.resource_is_being_initialized_ &&
|
| - !tile->priority(ACTIVE_TREE).is_live &&
|
| - !tile->priority(PENDING_TREE).is_live)
|
| - continue;
|
| -
|
| - live_or_allocated_tiles_.push_back(tile);
|
| - }
|
| - TRACE_COUNTER_ID1("cc", "LiveOrAllocatedTileCount", this,
|
| - live_or_allocated_tiles_.size());
|
| -
|
| - SortTiles();
|
| -
|
| - // Assign gpu memory and determine what tiles need to be rasterized.
|
| - AssignGpuMemoryToTiles();
|
| -
|
| - TRACE_EVENT_INSTANT1("cc", "DidManage", "state",
|
| - ValueToString(BasicStateAsValue()));
|
| -
|
| - // Finally, kick the rasterizer.
|
| - DispatchMoreTasks();
|
| -}
|
| -
|
| -void TileManager::CheckForCompletedTileUploads() {
|
| - while (!tiles_with_pending_upload_.empty()) {
|
| - Tile* tile = tiles_with_pending_upload_.front();
|
| - ManagedTileState& managed_tile_state = tile->managed_state();
|
| - DCHECK(managed_tile_state.drawing_info.resource_);
|
| -
|
| - // Set pixel tasks complete in the order they are posted.
|
| - if (!resource_pool_->resource_provider()->DidSetPixelsComplete(
|
| - managed_tile_state.drawing_info.resource_->id())) {
|
| - break;
|
| - }
|
| -
|
| - // It's now safe to release the pixel buffer.
|
| - resource_pool_->resource_provider()->ReleasePixelBuffer(
|
| - managed_tile_state.drawing_info.resource_->id());
|
| -
|
| - managed_tile_state.drawing_info.can_be_freed_ = true;
|
| -
|
| - bytes_pending_upload_ -= tile->bytes_consumed_if_allocated();
|
| - DidTileRasterStateChange(tile, IDLE_STATE);
|
| - DidFinishTileInitialization(tile);
|
| -
|
| - tiles_with_pending_upload_.pop();
|
| - }
|
| -
|
| - DispatchMoreTasks();
|
| -}
|
| -
|
| -void TileManager::AbortPendingTileUploads() {
|
| - while (!tiles_with_pending_upload_.empty()) {
|
| - Tile* tile = tiles_with_pending_upload_.front();
|
| - ManagedTileState& managed_tile_state = tile->managed_state();
|
| - DCHECK(managed_tile_state.drawing_info.resource_);
|
| -
|
| - resource_pool_->resource_provider()->AbortSetPixels(
|
| - managed_tile_state.drawing_info.resource_->id());
|
| - resource_pool_->resource_provider()->ReleasePixelBuffer(
|
| - managed_tile_state.drawing_info.resource_->id());
|
| -
|
| - managed_tile_state.drawing_info.resource_is_being_initialized_ = false;
|
| - managed_tile_state.drawing_info.can_be_freed_ = true;
|
| - managed_tile_state.can_use_gpu_memory = false;
|
| - FreeResourcesForTile(tile);
|
| -
|
| - bytes_pending_upload_ -= tile->bytes_consumed_if_allocated();
|
| - DidTileRasterStateChange(tile, IDLE_STATE);
|
| - tiles_with_pending_upload_.pop();
|
| - }
|
| -}
|
| -
|
| -void TileManager::DidCompleteFrame() {
|
| - allow_cheap_tasks_ = true;
|
| - did_schedule_cheap_tasks_ = false;
|
| -}
|
| -
|
| -void TileManager::ForceTileUploadToComplete(Tile* tile) {
|
| - ManagedTileState& managed_tile_state = tile->managed_state();
|
| - if (managed_tile_state.raster_state == UPLOAD_STATE) {
|
| - Resource* resource = tile->drawing_info().resource_.get();
|
| - DCHECK(resource);
|
| - resource_pool_->resource_provider()->
|
| - ForceSetPixelsToComplete(resource->id());
|
| - DidTileRasterStateChange(tile, FORCED_UPLOAD_COMPLETION_STATE);
|
| - DidFinishTileInitialization(tile);
|
| - }
|
| -}
|
| -
|
| -void TileManager::GetMemoryStats(
|
| - size_t* memoryRequiredBytes,
|
| - size_t* memoryNiceToHaveBytes,
|
| - size_t* memoryUsedBytes) const {
|
| - *memoryRequiredBytes = 0;
|
| - *memoryNiceToHaveBytes = 0;
|
| - *memoryUsedBytes = 0;
|
| - for (size_t i = 0; i < live_or_allocated_tiles_.size(); i++) {
|
| - const Tile* tile = live_or_allocated_tiles_[i];
|
| - const ManagedTileState& mts = tile->managed_state();
|
| - if (!tile->drawing_info().requires_resource())
|
| - continue;
|
| -
|
| - size_t tile_bytes = tile->bytes_consumed_if_allocated();
|
| - if (mts.gpu_memmgr_stats_bin == NOW_BIN)
|
| - *memoryRequiredBytes += tile_bytes;
|
| - if (mts.gpu_memmgr_stats_bin != NEVER_BIN)
|
| - *memoryNiceToHaveBytes += tile_bytes;
|
| - if (mts.can_use_gpu_memory)
|
| - *memoryUsedBytes += tile_bytes;
|
| - }
|
| -}
|
| -
|
| -scoped_ptr<base::Value> TileManager::BasicStateAsValue() const {
|
| - scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
|
| - state->SetInteger("tile_count", all_tiles_.size());
|
| - state->Set("global_state", global_state_.AsValue().release());
|
| - state->Set("memory_requirements", GetMemoryRequirementsAsValue().release());
|
| - return state.PassAs<base::Value>();
|
| -}
|
| -scoped_ptr<base::Value> TileManager::AllTilesAsValue() const {
|
| - scoped_ptr<base::ListValue> state(new base::ListValue());
|
| - for (TileSet::const_iterator it = all_tiles_.begin();
|
| - it != all_tiles_.end(); it++) {
|
| - state->Append((*it)->AsValue().release());
|
| - }
|
| - return state.PassAs<base::Value>();
|
| -}
|
| -
|
| -scoped_ptr<base::Value> TileManager::GetMemoryRequirementsAsValue() const {
|
| - scoped_ptr<base::DictionaryValue> requirements(
|
| - new base::DictionaryValue());
|
| -
|
| - size_t memoryRequiredBytes;
|
| - size_t memoryNiceToHaveBytes;
|
| - size_t memoryUsedBytes;
|
| - GetMemoryStats(&memoryRequiredBytes,
|
| - &memoryNiceToHaveBytes,
|
| - &memoryUsedBytes);
|
| - requirements->SetInteger("memory_required_bytes", memoryRequiredBytes);
|
| - requirements->SetInteger("memory_nice_to_have_bytes", memoryNiceToHaveBytes);
|
| - requirements->SetInteger("memory_used_bytes", memoryUsedBytes);
|
| - return requirements.PassAs<base::Value>();
|
| -}
|
| -
|
| -void TileManager::SetRecordRenderingStats(bool record_rendering_stats) {
|
| - if (record_rendering_stats_ == record_rendering_stats)
|
| - return;
|
| -
|
| - record_rendering_stats_ = record_rendering_stats;
|
| - raster_worker_pool_->SetRecordRenderingStats(record_rendering_stats);
|
| -}
|
| -
|
| -void TileManager::GetRenderingStats(RenderingStats* stats) {
|
| - CHECK(record_rendering_stats_);
|
| - raster_worker_pool_->GetRenderingStats(stats);
|
| - stats->totalDeferredImageCacheHitCount =
|
| - rendering_stats_.totalDeferredImageCacheHitCount;
|
| - stats->totalImageGatheringCount = rendering_stats_.totalImageGatheringCount;
|
| - stats->totalImageGatheringTime =
|
| - rendering_stats_.totalImageGatheringTime;
|
| -}
|
| -
|
| -bool TileManager::HasPendingWorkScheduled(WhichTree tree) const {
|
| - // Always true when ManageTiles() call is pending.
|
| - if (manage_tiles_pending_)
|
| - return true;
|
| -
|
| - for (int i = 0; i < NUM_STATES; ++i) {
|
| - switch (i) {
|
| - case WAITING_FOR_RASTER_STATE:
|
| - case RASTER_STATE:
|
| - case UPLOAD_STATE:
|
| - case FORCED_UPLOAD_COMPLETION_STATE:
|
| - for (int j = 0; j < NEVER_BIN; ++j) {
|
| - if (raster_state_count_[i][tree][j])
|
| - return true;
|
| - }
|
| - break;
|
| - case IDLE_STATE:
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -void TileManager::DidFinishDispatchingWorkerPoolCompletionCallbacks() {
|
| - // If a flush is needed, do it now before starting to dispatch more tasks.
|
| - if (has_performed_uploads_since_last_flush_) {
|
| - resource_pool_->resource_provider()->ShallowFlushIfSupported();
|
| - has_performed_uploads_since_last_flush_ = false;
|
| - }
|
| -
|
| - DispatchMoreTasks();
|
| -}
|
| -
|
| -void TileManager::AssignGpuMemoryToTiles() {
|
| - TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles");
|
| - size_t unreleasable_bytes = 0;
|
| -
|
| - // Now give memory out to the tiles until we're out, and build
|
| - // the needs-to-be-rasterized queue.
|
| - tiles_that_need_to_be_rasterized_.clear();
|
| -
|
| - // Reset the image decoding list so that we don't mess up with tile
|
| - // priorities. Tiles will be added to the image decoding list again
|
| - // when DispatchMoreTasks() is called.
|
| - tiles_with_image_decoding_tasks_.clear();
|
| -
|
| - // By clearing the tiles_that_need_to_be_rasterized_ vector and
|
| - // tiles_with_image_decoding_tasks_ list above we move all tiles
|
| - // currently waiting for raster to idle state.
|
| - // Call DidTileRasterStateChange() for each of these tiles to
|
| - // have this state change take effect.
|
| - // Some memory cannot be released. We figure out how much in this
|
| - // loop as well.
|
| - for (TileVector::iterator it = live_or_allocated_tiles_.begin();
|
| - it != live_or_allocated_tiles_.end(); ++it) {
|
| - Tile* tile = *it;
|
| - ManagedTileState& mts = tile->managed_state();
|
| - if (!tile->drawing_info().requires_resource())
|
| - continue;
|
| -
|
| - if (!mts.drawing_info.can_be_freed_)
|
| - unreleasable_bytes += tile->bytes_consumed_if_allocated();
|
| - if (mts.raster_state == WAITING_FOR_RASTER_STATE)
|
| - DidTileRasterStateChange(tile, IDLE_STATE);
|
| - }
|
| -
|
| - size_t bytes_allocatable = global_state_.memory_limit_in_bytes - unreleasable_bytes;
|
| - size_t bytes_that_exceeded_memory_budget_in_now_bin = 0;
|
| - size_t bytes_left = bytes_allocatable;
|
| - for (TileVector::iterator it = live_or_allocated_tiles_.begin(); it != live_or_allocated_tiles_.end(); ++it) {
|
| - Tile* tile = *it;
|
| - ManagedTileState& mts = tile->managed_state();
|
| - if (!tile->drawing_info().requires_resource())
|
| - continue;
|
| -
|
| - size_t tile_bytes = tile->bytes_consumed_if_allocated();
|
| - if (!mts.drawing_info.can_be_freed_)
|
| - continue;
|
| - if (mts.bin[HIGH_PRIORITY_BIN] == NEVER_BIN &&
|
| - mts.bin[LOW_PRIORITY_BIN] == NEVER_BIN) {
|
| - mts.can_use_gpu_memory = false;
|
| - FreeResourcesForTile(tile);
|
| - continue;
|
| - }
|
| - if (tile_bytes > bytes_left) {
|
| - mts.can_use_gpu_memory = false;
|
| - if (mts.bin[HIGH_PRIORITY_BIN] == NOW_BIN ||
|
| - mts.bin[LOW_PRIORITY_BIN] == NOW_BIN)
|
| - bytes_that_exceeded_memory_budget_in_now_bin += tile_bytes;
|
| - FreeResourcesForTile(tile);
|
| - continue;
|
| - }
|
| - bytes_left -= tile_bytes;
|
| - mts.can_use_gpu_memory = true;
|
| - if (!mts.drawing_info.resource_ &&
|
| - !mts.drawing_info.resource_is_being_initialized_) {
|
| - tiles_that_need_to_be_rasterized_.push_back(tile);
|
| - DidTileRasterStateChange(tile, WAITING_FOR_RASTER_STATE);
|
| - }
|
| - }
|
| -
|
| - ever_exceeded_memory_budget_ |=
|
| - bytes_that_exceeded_memory_budget_in_now_bin > 0;
|
| - if (ever_exceeded_memory_budget_) {
|
| - TRACE_COUNTER_ID2("cc", "over_memory_budget", this,
|
| - "budget", global_state_.memory_limit_in_bytes,
|
| - "over", bytes_that_exceeded_memory_budget_in_now_bin);
|
| - }
|
| - memory_stats_from_last_assign_.total_budget_in_bytes =
|
| - global_state_.memory_limit_in_bytes;
|
| - memory_stats_from_last_assign_.bytes_allocated =
|
| - bytes_allocatable - bytes_left;
|
| - memory_stats_from_last_assign_.bytes_unreleasable = unreleasable_bytes;
|
| - memory_stats_from_last_assign_.bytes_over =
|
| - bytes_that_exceeded_memory_budget_in_now_bin;
|
| -
|
| - // Reverse two tiles_that_need_* vectors such that pop_back gets
|
| - // the highest priority tile.
|
| - std::reverse(
|
| - tiles_that_need_to_be_rasterized_.begin(),
|
| - tiles_that_need_to_be_rasterized_.end());
|
| -}
|
| -
|
| -void TileManager::FreeResourcesForTile(Tile* tile) {
|
| - ManagedTileState& managed_tile_state = tile->managed_state();
|
| - DCHECK(managed_tile_state.drawing_info.can_be_freed_);
|
| - if (managed_tile_state.drawing_info.resource_)
|
| - resource_pool_->ReleaseResource(
|
| - managed_tile_state.drawing_info.resource_.Pass());
|
| -}
|
| -
|
| -bool TileManager::CanDispatchRasterTask(Tile* tile) const {
|
| - if (pending_tasks_ >= max_pending_tasks_)
|
| - return false;
|
| - size_t new_bytes_pending = bytes_pending_upload_;
|
| - new_bytes_pending += tile->bytes_consumed_if_allocated();
|
| - return new_bytes_pending <= kMaxPendingUploadBytes &&
|
| - tiles_with_pending_upload_.size() < kMaxPendingUploads;
|
| -}
|
| -
|
| -void TileManager::DispatchMoreTasks() {
|
| - if (did_schedule_cheap_tasks_)
|
| - allow_cheap_tasks_ = false;
|
| -
|
| - // 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. Note that solid/transparent tiles
|
| - // will not be put into the decoding list.
|
| - for(TileList::iterator it = tiles_with_image_decoding_tasks_.begin();
|
| - it != tiles_with_image_decoding_tasks_.end(); ) {
|
| - ManagedTileState& managed_tile_state = (*it)->managed_state();
|
| - DispatchImageDecodeTasksForTile(*it);
|
| - if (managed_tile_state.pending_pixel_refs.empty()) {
|
| - if (!CanDispatchRasterTask(*it))
|
| - return;
|
| - DispatchOneRasterTask(*it);
|
| - tiles_with_image_decoding_tasks_.erase(it++);
|
| - } else {
|
| - ++it;
|
| - }
|
| - }
|
| -
|
| - // Process all tiles in the need_to_be_rasterized queue. If a tile is
|
| - // solid/transparent, then we are done (we don't need to rasterize
|
| - // the tile). 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();
|
| - ManagedTileState& mts = tile->managed_state();
|
| -
|
| - AnalyzeTile(tile);
|
| - if (!tile->drawing_info().requires_resource()) {
|
| - DidTileRasterStateChange(tile, IDLE_STATE);
|
| - tiles_that_need_to_be_rasterized_.pop_back();
|
| - continue;
|
| - }
|
| -
|
| - DispatchImageDecodeTasksForTile(tile);
|
| - if (!mts.pending_pixel_refs.empty()) {
|
| - tiles_with_image_decoding_tasks_.push_back(tile);
|
| - } else {
|
| - if (!CanDispatchRasterTask(tile))
|
| - return;
|
| - DispatchOneRasterTask(tile);
|
| - }
|
| - tiles_that_need_to_be_rasterized_.pop_back();
|
| - }
|
| -}
|
| -
|
| -void TileManager::AnalyzeTile(Tile* tile) {
|
| - ManagedTileState& managed_tile_state = tile->managed_state();
|
| - if ((use_cheapness_estimator_ || use_color_estimator_) &&
|
| - !managed_tile_state.picture_pile_analyzed) {
|
| - tile->picture_pile()->AnalyzeInRect(
|
| - tile->content_rect(),
|
| - tile->contents_scale(),
|
| - &managed_tile_state.picture_pile_analysis);
|
| - managed_tile_state.picture_pile_analysis.is_cheap_to_raster &=
|
| - use_cheapness_estimator_;
|
| - managed_tile_state.picture_pile_analysis.is_solid_color &=
|
| - use_color_estimator_;
|
| - managed_tile_state.picture_pile_analysis.is_transparent &=
|
| - use_color_estimator_;
|
| - managed_tile_state.picture_pile_analyzed = true;
|
| -
|
| - if (managed_tile_state.picture_pile_analysis.is_solid_color) {
|
| - tile->drawing_info().set_solid_color(
|
| - managed_tile_state.picture_pile_analysis.solid_color);
|
| - DidFinishTileInitialization(tile);
|
| - } else if (managed_tile_state.picture_pile_analysis.is_transparent) {
|
| - tile->drawing_info().set_transparent();
|
| - DidFinishTileInitialization(tile);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void TileManager::GatherPixelRefsForTile(Tile* tile) {
|
| - TRACE_EVENT0("cc", "TileManager::GatherPixelRefsForTile");
|
| - ManagedTileState& managed_tile_state = tile->managed_state();
|
| - if (managed_tile_state.need_to_gather_pixel_refs) {
|
| - base::TimeTicks gather_begin_time;
|
| - if (record_rendering_stats_)
|
| - gather_begin_time = base::TimeTicks::HighResNow();
|
| - tile->picture_pile()->GatherPixelRefs(
|
| - tile->content_rect_,
|
| - tile->contents_scale_,
|
| - managed_tile_state.pending_pixel_refs);
|
| - managed_tile_state.need_to_gather_pixel_refs = false;
|
| - if (record_rendering_stats_) {
|
| - rendering_stats_.totalImageGatheringCount++;
|
| - rendering_stats_.totalImageGatheringTime +=
|
| - base::TimeTicks::HighResNow() - gather_begin_time;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void TileManager::DispatchImageDecodeTasksForTile(Tile* tile) {
|
| - GatherPixelRefsForTile(tile);
|
| - 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())) {
|
| - rendering_stats_.totalDeferredImageCacheHitCount++;
|
| - pending_pixel_refs.erase(it++);
|
| - } else {
|
| - if (pending_tasks_ >= max_pending_tasks_)
|
| - return;
|
| - DispatchOneImageDecodeTask(tile, *it);
|
| - ++it;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void TileManager::DispatchOneImageDecodeTask(
|
| - scoped_refptr<Tile> tile, skia::LazyPixelRef* pixel_ref) {
|
| - TRACE_EVENT0("cc", "TileManager::DispatchOneImageDecodeTask");
|
| - 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;
|
| -
|
| - raster_worker_pool_->PostTaskAndReply(
|
| - base::Bind(&TileManager::RunImageDecodeTask, pixel_ref),
|
| - base::Bind(&TileManager::OnImageDecodeTaskCompleted,
|
| - base::Unretained(this),
|
| - tile,
|
| - pixel_ref_id));
|
| - pending_tasks_++;
|
| -}
|
| -
|
| -void TileManager::OnImageDecodeTaskCompleted(
|
| - scoped_refptr<Tile> tile, uint32_t pixel_ref_id) {
|
| - TRACE_EVENT0("cc", "TileManager::OnImageDecodeTaskCompleted");
|
| - pending_decode_tasks_.erase(pixel_ref_id);
|
| - pending_tasks_--;
|
| -
|
| - 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;
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -scoped_ptr<ResourcePool::Resource> TileManager::PrepareTileForRaster(
|
| - Tile* tile) {
|
| - ManagedTileState& managed_tile_state = tile->managed_state();
|
| - DCHECK(managed_tile_state.can_use_gpu_memory);
|
| - scoped_ptr<ResourcePool::Resource> resource =
|
| - resource_pool_->AcquireResource(tile->tile_size_.size(), tile->format_);
|
| - resource_pool_->resource_provider()->AcquirePixelBuffer(resource->id());
|
| -
|
| - managed_tile_state.drawing_info.resource_is_being_initialized_ = true;
|
| - managed_tile_state.drawing_info.can_be_freed_ = false;
|
| -
|
| - DidTileRasterStateChange(tile, RASTER_STATE);
|
| - return resource.Pass();
|
| -}
|
| -
|
| -void TileManager::DispatchOneRasterTask(scoped_refptr<Tile> tile) {
|
| - TRACE_EVENT0("cc", "TileManager::DispatchOneRasterTask");
|
| - scoped_ptr<ResourcePool::Resource> resource = PrepareTileForRaster(tile);
|
| - ResourceProvider::ResourceId resource_id = resource->id();
|
| - uint8* buffer =
|
| - resource_pool_->resource_provider()->MapPixelBuffer(resource_id);
|
| -
|
| - ManagedTileState& managed_tile_state = tile->managed_state();
|
| - // TODO(skyostil): Post all cheap tasks as cheap and instead use the time
|
| - // limit to control their execution.
|
| - bool is_cheap_task =
|
| - allow_cheap_tasks_ &&
|
| - global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
|
| - managed_tile_state.picture_pile_analysis.is_cheap_to_raster;
|
| - raster_worker_pool_->PostRasterTaskAndReply(
|
| - tile->picture_pile(),
|
| - is_cheap_task,
|
| - base::Bind(&TileManager::RunRasterTask,
|
| - buffer,
|
| - tile->content_rect(),
|
| - tile->contents_scale(),
|
| - GetRasterTaskMetadata(*tile)),
|
| - base::Bind(&TileManager::OnRasterTaskCompleted,
|
| - base::Unretained(this),
|
| - tile,
|
| - base::Passed(&resource),
|
| - manage_tiles_call_count_));
|
| - if (is_cheap_task && !did_schedule_cheap_tasks_) {
|
| - raster_worker_pool_->SetRunCheapTasksTimeLimit(
|
| - base::TimeTicks::Now() +
|
| - base::TimeDelta::FromMilliseconds(kRunCheapTasksTimeMs));
|
| - did_schedule_cheap_tasks_ = true;
|
| - }
|
| - pending_tasks_++;
|
| -}
|
| -
|
| -TileManager::RasterTaskMetadata TileManager::GetRasterTaskMetadata(
|
| - const Tile& tile) const {
|
| - RasterTaskMetadata metadata;
|
| - const ManagedTileState& mts = tile.managed_state();
|
| - metadata.prediction_benchmarking = prediction_benchmarking_;
|
| - metadata.is_tile_in_pending_tree_now_bin =
|
| - mts.tree_bin[PENDING_TREE] == NOW_BIN;
|
| - metadata.tile_resolution = mts.resolution;
|
| - metadata.layer_id = tile.layer_id();
|
| - return metadata;
|
| -}
|
| -
|
| -void TileManager::OnRasterTaskCompleted(
|
| - scoped_refptr<Tile> tile,
|
| - scoped_ptr<ResourcePool::Resource> resource,
|
| - int manage_tiles_call_count_when_dispatched) {
|
| - TRACE_EVENT0("cc", "TileManager::OnRasterTaskCompleted");
|
| -
|
| - pending_tasks_--;
|
| -
|
| - // Release raster resources.
|
| - resource_pool_->resource_provider()->UnmapPixelBuffer(resource->id());
|
| -
|
| - ManagedTileState& managed_tile_state = tile->managed_state();
|
| - managed_tile_state.drawing_info.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 if ManageTiles() was called since task was dispatched. 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 DispatchMoreTasks().
|
| - if (manage_tiles_call_count_when_dispatched != manage_tiles_call_count_)
|
| - AssignGpuMemoryToTiles();
|
| -
|
| - // Finish resource initialization if |can_use_gpu_memory| is true.
|
| - if (managed_tile_state.can_use_gpu_memory) {
|
| - // The component order may be bgra if we're uploading bgra pixels to rgba
|
| - // texture. Mark contents as swizzled if image component order is
|
| - // different than texture format.
|
| - managed_tile_state.drawing_info.contents_swizzled_ =
|
| - !PlatformColor::SameComponentOrder(tile->format_);
|
| -
|
| - // Tile resources can't be freed until upload has completed.
|
| - managed_tile_state.drawing_info.can_be_freed_ = false;
|
| -
|
| - resource_pool_->resource_provider()->BeginSetPixels(resource->id());
|
| - has_performed_uploads_since_last_flush_ = true;
|
| -
|
| - managed_tile_state.drawing_info.resource_ = resource.Pass();
|
| -
|
| - bytes_pending_upload_ += tile->bytes_consumed_if_allocated();
|
| - DidTileRasterStateChange(tile, UPLOAD_STATE);
|
| - tiles_with_pending_upload_.push(tile);
|
| - } else {
|
| - resource_pool_->resource_provider()->ReleasePixelBuffer(resource->id());
|
| - resource_pool_->ReleaseResource(resource.Pass());
|
| - managed_tile_state.drawing_info.resource_is_being_initialized_ = false;
|
| - DidTileRasterStateChange(tile, IDLE_STATE);
|
| - }
|
| -}
|
| -
|
| -void TileManager::DidFinishTileInitialization(Tile* tile) {
|
| - ManagedTileState& managed_state = tile->managed_state();
|
| - managed_state.drawing_info.resource_is_being_initialized_ = false;
|
| - if (tile->priority(ACTIVE_TREE).distance_to_visible_in_pixels == 0)
|
| - client_->DidInitializeVisibleTile();
|
| -}
|
| -
|
| -void TileManager::DidTileRasterStateChange(Tile* tile, TileRasterState state) {
|
| - ManagedTileState& mts = tile->managed_state();
|
| - DCHECK_LT(state, NUM_STATES);
|
| -
|
| - for (int i = 0; i < NUM_TREES; ++i) {
|
| - // Decrement count for current state.
|
| - --raster_state_count_[mts.raster_state][i][mts.tree_bin[i]];
|
| - DCHECK_GE(raster_state_count_[mts.raster_state][i][mts.tree_bin[i]], 0);
|
| -
|
| - // Increment count for new state.
|
| - ++raster_state_count_[state][i][mts.tree_bin[i]];
|
| - }
|
| -
|
| - mts.raster_state = state;
|
| -}
|
| -
|
| -void TileManager::DidTileTreeBinChange(Tile* tile,
|
| - TileManagerBin new_tree_bin,
|
| - WhichTree tree) {
|
| - ManagedTileState& mts = tile->managed_state();
|
| -
|
| - // Decrement count for current bin.
|
| - --raster_state_count_[mts.raster_state][tree][mts.tree_bin[tree]];
|
| - DCHECK_GE(raster_state_count_[mts.raster_state][tree][mts.tree_bin[tree]], 0);
|
| -
|
| - // Increment count for new bin.
|
| - ++raster_state_count_[mts.raster_state][tree][new_tree_bin];
|
| -
|
| - mts.tree_bin[tree] = new_tree_bin;
|
| -}
|
| -
|
| -// static
|
| -void TileManager::RunRasterTask(uint8* buffer,
|
| - const gfx::Rect& rect,
|
| - float contents_scale,
|
| - const RasterTaskMetadata& metadata,
|
| - PicturePileImpl* picture_pile,
|
| - RenderingStats* stats) {
|
| - TRACE_EVENT2(
|
| - "cc", "TileManager::RunRasterTask",
|
| - "is_on_pending_tree",
|
| - metadata.is_tile_in_pending_tree_now_bin,
|
| - "is_low_res",
|
| - metadata.tile_resolution == LOW_RESOLUTION);
|
| - devtools_instrumentation::ScopedRasterTask raster_task(metadata.layer_id);
|
| -
|
| - DCHECK(picture_pile);
|
| - DCHECK(buffer);
|
| -
|
| - SkBitmap bitmap;
|
| - bitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
|
| - bitmap.setPixels(buffer);
|
| - SkDevice device(bitmap);
|
| - SkCanvas canvas(&device);
|
| -
|
| - base::TimeTicks begin_time;
|
| - if (stats)
|
| - begin_time = base::TimeTicks::HighResNow();
|
| -
|
| - int64 total_pixels_rasterized = 0;
|
| - picture_pile->Raster(&canvas, rect, contents_scale,
|
| - &total_pixels_rasterized);
|
| -
|
| - if (stats) {
|
| - stats->totalPixelsRasterized += total_pixels_rasterized;
|
| -
|
| - base::TimeTicks end_time = base::TimeTicks::HighResNow();
|
| - base::TimeDelta duration = end_time - begin_time;
|
| - stats->totalRasterizeTime += duration;
|
| - if (metadata.is_tile_in_pending_tree_now_bin)
|
| - stats->totalRasterizeTimeForNowBinsOnPendingTree += duration;
|
| -
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.PictureRasterTimeMS",
|
| - duration.InMilliseconds(),
|
| - 0,
|
| - 10,
|
| - 10);
|
| -
|
| - if (metadata.prediction_benchmarking) {
|
| - PicturePileImpl::Analysis analysis;
|
| - picture_pile->AnalyzeInRect(rect, contents_scale, &analysis);
|
| - bool is_predicted_cheap = analysis.is_cheap_to_raster;
|
| - bool is_actually_cheap = duration.InMillisecondsF() <= 1.0f;
|
| - RecordCheapnessPredictorResults(is_predicted_cheap, is_actually_cheap);
|
| -
|
| - DCHECK_EQ(bitmap.rowBytes(),
|
| - bitmap.width() * bitmap.bytesPerPixel());
|
| -
|
| - RecordSolidColorPredictorResults(
|
| - reinterpret_cast<SkColor*>(bitmap.getPixels()),
|
| - bitmap.getSize() / bitmap.bytesPerPixel(),
|
| - analysis.is_solid_color,
|
| - analysis.solid_color,
|
| - analysis.is_transparent);
|
| - }
|
| - }
|
| -}
|
| -
|
| -// static
|
| -void TileManager::RecordCheapnessPredictorResults(bool is_predicted_cheap,
|
| - bool is_actually_cheap) {
|
| - if (is_predicted_cheap && !is_actually_cheap)
|
| - UMA_HISTOGRAM_BOOLEAN("Renderer4.CheapPredictorBadlyWrong", true);
|
| - else if (!is_predicted_cheap && is_actually_cheap)
|
| - UMA_HISTOGRAM_BOOLEAN("Renderer4.CheapPredictorSafelyWrong", true);
|
| -
|
| - UMA_HISTOGRAM_BOOLEAN("Renderer4.CheapPredictorAccuracy",
|
| - is_predicted_cheap == is_actually_cheap);
|
| -}
|
| -
|
| -// static
|
| -void TileManager::RecordSolidColorPredictorResults(
|
| - const SkColor* actual_colors,
|
| - size_t color_count,
|
| - bool is_predicted_solid,
|
| - SkColor predicted_color,
|
| - bool is_predicted_transparent) {
|
| - DCHECK_GT(color_count, 0u);
|
| -
|
| - bool is_actually_solid = true;
|
| - bool is_transparent = true;
|
| -
|
| - SkColor actual_color = *actual_colors;
|
| - for (unsigned int i = 0; i < color_count; ++i) {
|
| - SkColor current_color = actual_colors[i];
|
| - if (current_color != actual_color ||
|
| - SkColorGetA(current_color) != 255)
|
| - is_actually_solid = false;
|
| -
|
| - if (SkColorGetA(current_color) != 0)
|
| - is_transparent = false;
|
| -
|
| - if(!is_actually_solid && !is_transparent)
|
| - break;
|
| - }
|
| -
|
| - if (is_predicted_solid && !is_actually_solid)
|
| - UMA_HISTOGRAM_BOOLEAN("Renderer4.ColorPredictor.WrongActualNotSolid", true);
|
| - else if (is_predicted_solid &&
|
| - is_actually_solid &&
|
| - predicted_color != actual_color)
|
| - UMA_HISTOGRAM_BOOLEAN("Renderer4.ColorPredictor.WrongColor", true);
|
| - else if (!is_predicted_solid && is_actually_solid)
|
| - UMA_HISTOGRAM_BOOLEAN("Renderer4.ColorPredictor.WrongActualSolid", true);
|
| -
|
| - bool correct_guess = (is_predicted_solid && is_actually_solid &&
|
| - predicted_color == actual_color) ||
|
| - (!is_predicted_solid && !is_actually_solid);
|
| - UMA_HISTOGRAM_BOOLEAN("Renderer4.ColorPredictor.Accuracy", correct_guess);
|
| -
|
| - if (correct_guess)
|
| - UMA_HISTOGRAM_BOOLEAN("Renderer4.ColorPredictor.IsCorrectSolid",
|
| - is_predicted_solid);
|
| -
|
| - if (is_predicted_transparent)
|
| - UMA_HISTOGRAM_BOOLEAN(
|
| - "Renderer4.ColorPredictor.PredictedTransparentIsActually",
|
| - is_transparent);
|
| - UMA_HISTOGRAM_BOOLEAN("Renderer4.ColorPredictor.IsActuallyTransparent",
|
| - is_transparent);
|
| -}
|
| -
|
| -// static
|
| -void TileManager::RunImageDecodeTask(skia::LazyPixelRef* pixel_ref,
|
| - RenderingStats* stats) {
|
| - TRACE_EVENT0("cc", "TileManager::RunImageDecodeTask");
|
| - base::TimeTicks decode_begin_time;
|
| - if (stats)
|
| - decode_begin_time = base::TimeTicks::HighResNow();
|
| - pixel_ref->Decode();
|
| - if (stats) {
|
| - stats->totalDeferredImageDecodeCount++;
|
| - stats->totalDeferredImageDecodeTime +=
|
| - base::TimeTicks::HighResNow() - decode_begin_time;
|
| - }
|
| -}
|
| -
|
| -} // namespace cc
|
|
|