Index: cc/resources/tile_manager.cc |
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc |
deleted file mode 100644 |
index 6cd02399863ba5f711017518f7c450a28875fa07..0000000000000000000000000000000000000000 |
--- a/cc/resources/tile_manager.cc |
+++ /dev/null |
@@ -1,975 +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/resources/tile_manager.h" |
- |
-#include <algorithm> |
-#include <limits> |
-#include <string> |
- |
-#include "base/bind.h" |
-#include "base/json/json_writer.h" |
-#include "base/logging.h" |
-#include "base/metrics/histogram.h" |
-#include "base/trace_event/trace_event_argument.h" |
-#include "cc/debug/devtools_instrumentation.h" |
-#include "cc/debug/frame_viewer_instrumentation.h" |
-#include "cc/debug/traced_value.h" |
-#include "cc/layers/picture_layer_impl.h" |
-#include "cc/resources/raster_buffer.h" |
-#include "cc/resources/tile.h" |
-#include "cc/resources/tile_task_runner.h" |
-#include "ui/gfx/geometry/rect_conversions.h" |
- |
-namespace cc { |
-namespace { |
- |
-// Flag to indicate whether we should try and detect that |
-// a tile is of solid color. |
-const bool kUseColorEstimator = true; |
- |
-class RasterTaskImpl : public RasterTask { |
- public: |
- RasterTaskImpl( |
- const Resource* resource, |
- RasterSource* raster_source, |
- const gfx::Rect& content_rect, |
- float contents_scale, |
- TileResolution tile_resolution, |
- int layer_id, |
- const void* tile_id, |
- int source_frame_number, |
- bool analyze_picture, |
- const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>& |
- reply, |
- ImageDecodeTask::Vector* dependencies) |
- : RasterTask(resource, dependencies), |
- raster_source_(raster_source), |
- content_rect_(content_rect), |
- contents_scale_(contents_scale), |
- tile_resolution_(tile_resolution), |
- layer_id_(layer_id), |
- tile_id_(tile_id), |
- source_frame_number_(source_frame_number), |
- analyze_picture_(analyze_picture), |
- reply_(reply) {} |
- |
- // Overridden from Task: |
- void RunOnWorkerThread() override { |
- TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread"); |
- |
- DCHECK(raster_source_.get()); |
- DCHECK(raster_buffer_); |
- |
- if (analyze_picture_) { |
- Analyze(raster_source_.get()); |
- if (analysis_.is_solid_color) |
- return; |
- } |
- |
- Raster(raster_source_.get()); |
- } |
- |
- // Overridden from TileTask: |
- void ScheduleOnOriginThread(TileTaskClient* client) override { |
- DCHECK(!raster_buffer_); |
- raster_buffer_ = client->AcquireBufferForRaster(resource()); |
- } |
- void CompleteOnOriginThread(TileTaskClient* client) override { |
- client->ReleaseBufferForRaster(raster_buffer_.Pass()); |
- } |
- void RunReplyOnOriginThread() override { |
- DCHECK(!raster_buffer_); |
- reply_.Run(analysis_, !HasFinishedRunning()); |
- } |
- |
- protected: |
- ~RasterTaskImpl() override { DCHECK(!raster_buffer_); } |
- |
- private: |
- void Analyze(const RasterSource* raster_source) { |
- frame_viewer_instrumentation::ScopedAnalyzeTask analyze_task( |
- tile_id_, tile_resolution_, source_frame_number_, layer_id_); |
- |
- DCHECK(raster_source); |
- |
- raster_source->PerformSolidColorAnalysis(content_rect_, contents_scale_, |
- &analysis_); |
- // Clear the flag if we're not using the estimator. |
- analysis_.is_solid_color &= kUseColorEstimator; |
- } |
- |
- void Raster(const RasterSource* raster_source) { |
- frame_viewer_instrumentation::ScopedRasterTask raster_task( |
- tile_id_, tile_resolution_, source_frame_number_, layer_id_); |
- |
- DCHECK(raster_source); |
- |
- raster_buffer_->Playback(raster_source_.get(), content_rect_, |
- contents_scale_); |
- } |
- |
- RasterSource::SolidColorAnalysis analysis_; |
- scoped_refptr<RasterSource> raster_source_; |
- gfx::Rect content_rect_; |
- float contents_scale_; |
- TileResolution tile_resolution_; |
- int layer_id_; |
- const void* tile_id_; |
- int source_frame_number_; |
- bool analyze_picture_; |
- const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)> |
- reply_; |
- scoped_ptr<RasterBuffer> raster_buffer_; |
- |
- DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl); |
-}; |
- |
-class ImageDecodeTaskImpl : public ImageDecodeTask { |
- public: |
- ImageDecodeTaskImpl(SkPixelRef* pixel_ref, |
- const base::Callback<void(bool was_canceled)>& reply) |
- : pixel_ref_(skia::SharePtr(pixel_ref)), |
- reply_(reply) {} |
- |
- // Overridden from Task: |
- void RunOnWorkerThread() override { |
- TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread"); |
- |
- devtools_instrumentation::ScopedImageDecodeTask image_decode_task( |
- pixel_ref_.get()); |
- // This will cause the image referred to by pixel ref to be decoded. |
- pixel_ref_->lockPixels(); |
- pixel_ref_->unlockPixels(); |
- |
- // Release the reference after decoding image to ensure that it is not |
- // kept alive unless needed. |
- pixel_ref_.clear(); |
- } |
- |
- // Overridden from TileTask: |
- void ScheduleOnOriginThread(TileTaskClient* client) override {} |
- void CompleteOnOriginThread(TileTaskClient* client) override {} |
- void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); } |
- |
- protected: |
- ~ImageDecodeTaskImpl() override {} |
- |
- private: |
- skia::RefPtr<SkPixelRef> pixel_ref_; |
- const base::Callback<void(bool was_canceled)> reply_; |
- |
- DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl); |
-}; |
- |
-const char* TaskSetName(TaskSet task_set) { |
- switch (task_set) { |
- case TileManager::ALL: |
- return "ALL"; |
- case TileManager::REQUIRED_FOR_ACTIVATION: |
- return "REQUIRED_FOR_ACTIVATION"; |
- case TileManager::REQUIRED_FOR_DRAW: |
- return "REQUIRED_FOR_DRAW"; |
- } |
- |
- NOTREACHED(); |
- return "Invalid TaskSet"; |
-} |
- |
-} // namespace |
- |
-RasterTaskCompletionStats::RasterTaskCompletionStats() |
- : completed_count(0u), canceled_count(0u) {} |
- |
-scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
-RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) { |
- scoped_refptr<base::trace_event::TracedValue> state = |
- new base::trace_event::TracedValue(); |
- state->SetInteger("completed_count", stats.completed_count); |
- state->SetInteger("canceled_count", stats.canceled_count); |
- return state; |
-} |
- |
-// static |
-scoped_ptr<TileManager> TileManager::Create( |
- TileManagerClient* client, |
- base::SequencedTaskRunner* task_runner, |
- ResourcePool* resource_pool, |
- TileTaskRunner* tile_task_runner, |
- size_t scheduled_raster_task_limit) { |
- return make_scoped_ptr(new TileManager(client, task_runner, resource_pool, |
- tile_task_runner, |
- scheduled_raster_task_limit)); |
-} |
- |
-TileManager::TileManager( |
- TileManagerClient* client, |
- const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
- ResourcePool* resource_pool, |
- TileTaskRunner* tile_task_runner, |
- size_t scheduled_raster_task_limit) |
- : client_(client), |
- task_runner_(task_runner), |
- resource_pool_(resource_pool), |
- tile_task_runner_(tile_task_runner), |
- scheduled_raster_task_limit_(scheduled_raster_task_limit), |
- all_tiles_that_need_to_be_rasterized_are_scheduled_(true), |
- did_check_for_completed_tasks_since_last_schedule_tasks_(true), |
- did_oom_on_last_assign_(false), |
- ready_to_activate_check_notifier_( |
- task_runner_.get(), |
- base::Bind(&TileManager::CheckIfReadyToActivate, |
- base::Unretained(this))), |
- ready_to_draw_check_notifier_( |
- task_runner_.get(), |
- base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))), |
- more_tiles_need_prepare_check_notifier_( |
- task_runner_.get(), |
- base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared, |
- base::Unretained(this))), |
- did_notify_ready_to_activate_(false), |
- did_notify_ready_to_draw_(false) { |
- tile_task_runner_->SetClient(this); |
-} |
- |
-TileManager::~TileManager() { |
- // Reset global state and manage. This should cause |
- // our memory usage to drop to zero. |
- global_state_ = GlobalStateThatImpactsTilePriority(); |
- |
- TileTaskQueue empty; |
- tile_task_runner_->ScheduleTasks(&empty); |
- orphan_raster_tasks_.clear(); |
- |
- // This should finish all pending tasks and release any uninitialized |
- // resources. |
- tile_task_runner_->Shutdown(); |
- tile_task_runner_->CheckForCompletedTasks(); |
- |
- FreeResourcesForReleasedTiles(); |
- CleanUpReleasedTiles(); |
-} |
- |
-void TileManager::Release(Tile* tile) { |
- released_tiles_.push_back(tile); |
-} |
- |
-TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const { |
- TaskSetCollection tasks_that_should_be_forced_to_complete; |
- if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY) |
- tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true; |
- return tasks_that_should_be_forced_to_complete; |
-} |
- |
-void TileManager::FreeResourcesForReleasedTiles() { |
- for (auto* tile : released_tiles_) |
- FreeResourcesForTile(tile); |
-} |
- |
-void TileManager::CleanUpReleasedTiles() { |
- std::vector<Tile*> tiles_to_retain; |
- for (auto* tile : released_tiles_) { |
- if (tile->HasRasterTask()) { |
- tiles_to_retain.push_back(tile); |
- continue; |
- } |
- |
- DCHECK(!tile->draw_info().has_resource()); |
- DCHECK(tiles_.find(tile->id()) != tiles_.end()); |
- tiles_.erase(tile->id()); |
- |
- LayerCountMap::iterator layer_it = |
- used_layer_counts_.find(tile->layer_id()); |
- DCHECK_GT(layer_it->second, 0); |
- if (--layer_it->second == 0) { |
- used_layer_counts_.erase(layer_it); |
- image_decode_tasks_.erase(tile->layer_id()); |
- } |
- |
- delete tile; |
- } |
- released_tiles_.swap(tiles_to_retain); |
-} |
- |
-void TileManager::DidFinishRunningTileTasks(TaskSet task_set) { |
- TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set", |
- TaskSetName(task_set)); |
- |
- switch (task_set) { |
- case ALL: { |
- bool memory_usage_above_limit = |
- resource_pool_->total_memory_usage_bytes() > |
- global_state_.soft_memory_limit_in_bytes; |
- |
- if (all_tiles_that_need_to_be_rasterized_are_scheduled_ && |
- !memory_usage_above_limit) |
- return; |
- |
- more_tiles_need_prepare_check_notifier_.Schedule(); |
- return; |
- } |
- case REQUIRED_FOR_ACTIVATION: |
- ready_to_activate_check_notifier_.Schedule(); |
- return; |
- case REQUIRED_FOR_DRAW: |
- ready_to_draw_check_notifier_.Schedule(); |
- return; |
- } |
- |
- NOTREACHED(); |
-} |
- |
-void TileManager::PrepareTiles( |
- const GlobalStateThatImpactsTilePriority& state) { |
- TRACE_EVENT0("cc", "TileManager::PrepareTiles"); |
- |
- global_state_ = state; |
- |
- // We need to call CheckForCompletedTasks() once in-between each call |
- // to ScheduleTasks() to prevent canceled tasks from being scheduled. |
- if (!did_check_for_completed_tasks_since_last_schedule_tasks_) { |
- tile_task_runner_->CheckForCompletedTasks(); |
- did_check_for_completed_tasks_since_last_schedule_tasks_ = true; |
- } |
- |
- FreeResourcesForReleasedTiles(); |
- CleanUpReleasedTiles(); |
- |
- PrioritizedTileVector tiles_that_need_to_be_rasterized; |
- scoped_ptr<RasterTilePriorityQueue> raster_priority_queue( |
- client_->BuildRasterQueue(global_state_.tree_priority, |
- RasterTilePriorityQueue::Type::ALL)); |
- AssignGpuMemoryToTiles(raster_priority_queue.get(), |
- scheduled_raster_task_limit_, |
- &tiles_that_need_to_be_rasterized); |
- |
- // Inform the client that will likely require a draw if the highest priority |
- // tile that will be rasterized is required for draw. |
- client_->SetIsLikelyToRequireADraw( |
- !tiles_that_need_to_be_rasterized.empty() && |
- tiles_that_need_to_be_rasterized.front().tile()->required_for_draw()); |
- |
- // Schedule tile tasks. |
- ScheduleTasks(tiles_that_need_to_be_rasterized); |
- |
- did_notify_ready_to_activate_ = false; |
- did_notify_ready_to_draw_ = false; |
- |
- TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD, |
- "state", BasicStateAsValue()); |
- |
- TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this, |
- resource_pool_->total_memory_usage_bytes() - |
- resource_pool_->acquired_memory_usage_bytes()); |
-} |
- |
-void TileManager::UpdateVisibleTiles( |
- const GlobalStateThatImpactsTilePriority& state) { |
- TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles"); |
- |
- tile_task_runner_->CheckForCompletedTasks(); |
- |
- did_check_for_completed_tasks_since_last_schedule_tasks_ = true; |
- |
- TRACE_EVENT_INSTANT1( |
- "cc", |
- "DidUpdateVisibleTiles", |
- TRACE_EVENT_SCOPE_THREAD, |
- "stats", |
- RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_)); |
- update_visible_tiles_stats_ = RasterTaskCompletionStats(); |
-} |
- |
-scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
-TileManager::BasicStateAsValue() const { |
- scoped_refptr<base::trace_event::TracedValue> value = |
- new base::trace_event::TracedValue(); |
- BasicStateAsValueInto(value.get()); |
- return value; |
-} |
- |
-void TileManager::BasicStateAsValueInto( |
- base::trace_event::TracedValue* state) const { |
- state->SetInteger("tile_count", tiles_.size()); |
- state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_); |
- state->BeginDictionary("global_state"); |
- global_state_.AsValueInto(state); |
- state->EndDictionary(); |
-} |
- |
-scoped_ptr<EvictionTilePriorityQueue> |
-TileManager::FreeTileResourcesUntilUsageIsWithinLimit( |
- scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue, |
- const MemoryUsage& limit, |
- MemoryUsage* usage) { |
- while (usage->Exceeds(limit)) { |
- if (!eviction_priority_queue) { |
- eviction_priority_queue = |
- client_->BuildEvictionQueue(global_state_.tree_priority); |
- } |
- if (eviction_priority_queue->IsEmpty()) |
- break; |
- |
- Tile* tile = eviction_priority_queue->Top().tile(); |
- *usage -= MemoryUsage::FromTile(tile); |
- FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); |
- eviction_priority_queue->Pop(); |
- } |
- return eviction_priority_queue; |
-} |
- |
-scoped_ptr<EvictionTilePriorityQueue> |
-TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit( |
- scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue, |
- const MemoryUsage& limit, |
- const TilePriority& other_priority, |
- MemoryUsage* usage) { |
- while (usage->Exceeds(limit)) { |
- if (!eviction_priority_queue) { |
- eviction_priority_queue = |
- client_->BuildEvictionQueue(global_state_.tree_priority); |
- } |
- if (eviction_priority_queue->IsEmpty()) |
- break; |
- |
- const PrioritizedTile& prioritized_tile = eviction_priority_queue->Top(); |
- if (!other_priority.IsHigherPriorityThan(prioritized_tile.priority())) |
- break; |
- |
- Tile* tile = prioritized_tile.tile(); |
- *usage -= MemoryUsage::FromTile(tile); |
- FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); |
- eviction_priority_queue->Pop(); |
- } |
- return eviction_priority_queue; |
-} |
- |
-bool TileManager::TilePriorityViolatesMemoryPolicy( |
- const TilePriority& priority) { |
- switch (global_state_.memory_limit_policy) { |
- case ALLOW_NOTHING: |
- return true; |
- case ALLOW_ABSOLUTE_MINIMUM: |
- return priority.priority_bin > TilePriority::NOW; |
- case ALLOW_PREPAINT_ONLY: |
- return priority.priority_bin > TilePriority::SOON; |
- case ALLOW_ANYTHING: |
- return priority.distance_to_visible == |
- std::numeric_limits<float>::infinity(); |
- } |
- NOTREACHED(); |
- return true; |
-} |
- |
-void TileManager::AssignGpuMemoryToTiles( |
- RasterTilePriorityQueue* raster_priority_queue, |
- size_t scheduled_raster_task_limit, |
- PrioritizedTileVector* tiles_that_need_to_be_rasterized) { |
- TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles"); |
- |
- // Maintain the list of released resources that can potentially be re-used |
- // or deleted. If this operation becomes expensive too, only do this after |
- // some resource(s) was returned. Note that in that case, one also need to |
- // invalidate when releasing some resource from the pool. |
- resource_pool_->CheckBusyResources(false); |
- |
- // Now give memory out to the tiles until we're out, and build |
- // the needs-to-be-rasterized queue. |
- unsigned schedule_priority = 1u; |
- all_tiles_that_need_to_be_rasterized_are_scheduled_ = true; |
- bool had_enough_memory_to_schedule_tiles_needed_now = true; |
- |
- MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes, |
- global_state_.num_resources_limit); |
- MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes, |
- global_state_.num_resources_limit); |
- MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(), |
- resource_pool_->acquired_resource_count()); |
- |
- scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue; |
- for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) { |
- const PrioritizedTile& prioritized_tile = raster_priority_queue->Top(); |
- Tile* tile = prioritized_tile.tile(); |
- TilePriority priority = prioritized_tile.priority(); |
- |
- if (TilePriorityViolatesMemoryPolicy(priority)) { |
- TRACE_EVENT_INSTANT0( |
- "cc", "TileManager::AssignGpuMemory tile violates memory policy", |
- TRACE_EVENT_SCOPE_THREAD); |
- break; |
- } |
- |
- // We won't be able to schedule this tile, so break out early. |
- if (tiles_that_need_to_be_rasterized->size() >= |
- scheduled_raster_task_limit) { |
- all_tiles_that_need_to_be_rasterized_are_scheduled_ = false; |
- break; |
- } |
- |
- tile->scheduled_priority_ = schedule_priority++; |
- |
- DCHECK_IMPLIES(tile->draw_info().mode() != TileDrawInfo::OOM_MODE, |
- !tile->draw_info().IsReadyToDraw()); |
- |
- // If the tile already has a raster_task, then the memory used by it is |
- // already accounted for in memory_usage. Otherwise, we'll have to acquire |
- // more memory to create a raster task. |
- MemoryUsage memory_required_by_tile_to_be_scheduled; |
- if (!tile->raster_task_.get()) { |
- memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig( |
- tile->desired_texture_size(), tile_task_runner_->GetResourceFormat()); |
- } |
- |
- bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW; |
- |
- // This is the memory limit that will be used by this tile. Depending on |
- // the tile priority, it will be one of hard_memory_limit or |
- // soft_memory_limit. |
- MemoryUsage& tile_memory_limit = |
- tile_is_needed_now ? hard_memory_limit : soft_memory_limit; |
- |
- const MemoryUsage& scheduled_tile_memory_limit = |
- tile_memory_limit - memory_required_by_tile_to_be_scheduled; |
- eviction_priority_queue = |
- FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit( |
- eviction_priority_queue.Pass(), scheduled_tile_memory_limit, |
- priority, &memory_usage); |
- bool memory_usage_is_within_limit = |
- !memory_usage.Exceeds(scheduled_tile_memory_limit); |
- |
- // If we couldn't fit the tile into our current memory limit, then we're |
- // done. |
- if (!memory_usage_is_within_limit) { |
- if (tile_is_needed_now) |
- had_enough_memory_to_schedule_tiles_needed_now = false; |
- all_tiles_that_need_to_be_rasterized_are_scheduled_ = false; |
- break; |
- } |
- |
- memory_usage += memory_required_by_tile_to_be_scheduled; |
- tiles_that_need_to_be_rasterized->push_back(prioritized_tile); |
- } |
- |
- // Note that we should try and further reduce memory in case the above loop |
- // didn't reduce memory. This ensures that we always release as many resources |
- // as possible to stay within the memory limit. |
- eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit( |
- eviction_priority_queue.Pass(), hard_memory_limit, &memory_usage); |
- |
- UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget", |
- !had_enough_memory_to_schedule_tiles_needed_now); |
- did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now; |
- |
- memory_stats_from_last_assign_.total_budget_in_bytes = |
- global_state_.hard_memory_limit_in_bytes; |
- memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes(); |
- memory_stats_from_last_assign_.had_enough_memory = |
- had_enough_memory_to_schedule_tiles_needed_now; |
- |
- TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles", |
- "all_tiles_that_need_to_be_rasterized_are_scheduled", |
- all_tiles_that_need_to_be_rasterized_are_scheduled_, |
- "had_enough_memory_to_schedule_tiles_needed_now", |
- had_enough_memory_to_schedule_tiles_needed_now); |
-} |
- |
-void TileManager::FreeResourcesForTile(Tile* tile) { |
- TileDrawInfo& draw_info = tile->draw_info(); |
- if (draw_info.resource_) |
- resource_pool_->ReleaseResource(draw_info.resource_.Pass()); |
-} |
- |
-void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw( |
- Tile* tile) { |
- bool was_ready_to_draw = tile->draw_info().IsReadyToDraw(); |
- FreeResourcesForTile(tile); |
- if (was_ready_to_draw) |
- client_->NotifyTileStateChanged(tile); |
-} |
- |
-void TileManager::ScheduleTasks( |
- const PrioritizedTileVector& tiles_that_need_to_be_rasterized) { |
- TRACE_EVENT1("cc", |
- "TileManager::ScheduleTasks", |
- "count", |
- tiles_that_need_to_be_rasterized.size()); |
- |
- DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_); |
- |
- raster_queue_.Reset(); |
- |
- // Build a new task queue containing all task currently needed. Tasks |
- // are added in order of priority, highest priority task first. |
- for (auto& prioritized_tile : tiles_that_need_to_be_rasterized) { |
- Tile* tile = prioritized_tile.tile(); |
- |
- DCHECK(tile->draw_info().requires_resource()); |
- DCHECK(!tile->draw_info().resource_); |
- |
- if (!tile->raster_task_.get()) |
- tile->raster_task_ = CreateRasterTask(prioritized_tile); |
- |
- TaskSetCollection task_sets; |
- if (tile->required_for_activation()) |
- task_sets.set(REQUIRED_FOR_ACTIVATION); |
- if (tile->required_for_draw()) |
- task_sets.set(REQUIRED_FOR_DRAW); |
- task_sets.set(ALL); |
- raster_queue_.items.push_back( |
- TileTaskQueue::Item(tile->raster_task_.get(), task_sets)); |
- } |
- |
- // We must reduce the amount of unused resoruces before calling |
- // ScheduleTasks to prevent usage from rising above limits. |
- resource_pool_->ReduceResourceUsage(); |
- |
- // Schedule running of |raster_queue_|. This replaces any previously |
- // scheduled tasks and effectively cancels all tasks not present |
- // in |raster_queue_|. |
- tile_task_runner_->ScheduleTasks(&raster_queue_); |
- |
- // It's now safe to clean up orphan tasks as raster worker pool is not |
- // allowed to keep around unreferenced raster tasks after ScheduleTasks() has |
- // been called. |
- orphan_raster_tasks_.clear(); |
- |
- did_check_for_completed_tasks_since_last_schedule_tasks_ = false; |
-} |
- |
-scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask( |
- Tile* tile, |
- SkPixelRef* pixel_ref) { |
- return make_scoped_refptr(new ImageDecodeTaskImpl( |
- pixel_ref, |
- base::Bind(&TileManager::OnImageDecodeTaskCompleted, |
- base::Unretained(this), |
- tile->layer_id(), |
- base::Unretained(pixel_ref)))); |
-} |
- |
-scoped_refptr<RasterTask> TileManager::CreateRasterTask( |
- const PrioritizedTile& prioritized_tile) { |
- Tile* tile = prioritized_tile.tile(); |
- scoped_ptr<ScopedResource> resource = |
- resource_pool_->AcquireResource(tile->desired_texture_size(), |
- tile_task_runner_->GetResourceFormat()); |
- const ScopedResource* const_resource = resource.get(); |
- |
- // Create and queue all image decode tasks that this tile depends on. |
- ImageDecodeTask::Vector decode_tasks; |
- PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()]; |
- std::vector<SkPixelRef*> pixel_refs; |
- prioritized_tile.raster_source()->GatherPixelRefs( |
- tile->content_rect(), tile->contents_scale(), &pixel_refs); |
- for (SkPixelRef* pixel_ref : pixel_refs) { |
- uint32_t id = pixel_ref->getGenerationID(); |
- |
- // Append existing image decode task if available. |
- PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id); |
- if (decode_task_it != existing_pixel_refs.end()) { |
- decode_tasks.push_back(decode_task_it->second); |
- continue; |
- } |
- |
- // Create and append new image decode task for this pixel ref. |
- scoped_refptr<ImageDecodeTask> decode_task = |
- CreateImageDecodeTask(tile, pixel_ref); |
- decode_tasks.push_back(decode_task); |
- existing_pixel_refs[id] = decode_task; |
- } |
- |
- return make_scoped_refptr(new RasterTaskImpl( |
- const_resource, prioritized_tile.raster_source(), tile->content_rect(), |
- tile->contents_scale(), prioritized_tile.priority().resolution, |
- tile->layer_id(), static_cast<const void*>(tile), |
- tile->source_frame_number(), tile->use_picture_analysis(), |
- base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this), |
- tile->id(), base::Passed(&resource)), |
- &decode_tasks)); |
-} |
- |
-void TileManager::OnImageDecodeTaskCompleted(int layer_id, |
- SkPixelRef* pixel_ref, |
- bool was_canceled) { |
- // If the task was canceled, we need to clean it up |
- // from |image_decode_tasks_|. |
- if (!was_canceled) |
- return; |
- |
- LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id); |
- if (layer_it == image_decode_tasks_.end()) |
- return; |
- |
- PixelRefTaskMap& pixel_ref_tasks = layer_it->second; |
- PixelRefTaskMap::iterator task_it = |
- pixel_ref_tasks.find(pixel_ref->getGenerationID()); |
- |
- if (task_it != pixel_ref_tasks.end()) |
- pixel_ref_tasks.erase(task_it); |
-} |
- |
-void TileManager::OnRasterTaskCompleted( |
- Tile::Id tile_id, |
- scoped_ptr<ScopedResource> resource, |
- const RasterSource::SolidColorAnalysis& analysis, |
- bool was_canceled) { |
- DCHECK(tiles_.find(tile_id) != tiles_.end()); |
- |
- Tile* tile = tiles_[tile_id]; |
- DCHECK(tile->raster_task_.get()); |
- orphan_raster_tasks_.push_back(tile->raster_task_); |
- tile->raster_task_ = nullptr; |
- |
- if (was_canceled) { |
- ++update_visible_tiles_stats_.canceled_count; |
- resource_pool_->ReleaseResource(resource.Pass()); |
- return; |
- } |
- |
- UpdateTileDrawInfo(tile, resource.Pass(), analysis); |
-} |
- |
-void TileManager::UpdateTileDrawInfo( |
- Tile* tile, |
- scoped_ptr<ScopedResource> resource, |
- const RasterSource::SolidColorAnalysis& analysis) { |
- TileDrawInfo& draw_info = tile->draw_info(); |
- |
- ++update_visible_tiles_stats_.completed_count; |
- |
- if (analysis.is_solid_color) { |
- draw_info.set_solid_color(analysis.solid_color); |
- if (resource) |
- resource_pool_->ReleaseResource(resource.Pass()); |
- } else { |
- DCHECK(resource); |
- draw_info.set_use_resource(); |
- draw_info.resource_ = resource.Pass(); |
- } |
- |
- client_->NotifyTileStateChanged(tile); |
-} |
- |
-ScopedTilePtr TileManager::CreateTile(const gfx::Size& desired_texture_size, |
- const gfx::Rect& content_rect, |
- float contents_scale, |
- int layer_id, |
- int source_frame_number, |
- int flags) { |
- ScopedTilePtr tile(new Tile(this, desired_texture_size, content_rect, |
- contents_scale, layer_id, source_frame_number, |
- flags)); |
- DCHECK(tiles_.find(tile->id()) == tiles_.end()); |
- |
- tiles_[tile->id()] = tile.get(); |
- used_layer_counts_[tile->layer_id()]++; |
- return tile; |
-} |
- |
-void TileManager::SetTileTaskRunnerForTesting( |
- TileTaskRunner* tile_task_runner) { |
- tile_task_runner_ = tile_task_runner; |
- tile_task_runner_->SetClient(this); |
-} |
- |
-bool TileManager::AreRequiredTilesReadyToDraw( |
- RasterTilePriorityQueue::Type type) const { |
- scoped_ptr<RasterTilePriorityQueue> raster_priority_queue( |
- client_->BuildRasterQueue(global_state_.tree_priority, type)); |
- // It is insufficient to check whether the raster queue we constructed is |
- // empty. The reason for this is that there are situations (rasterize on |
- // demand) when the tile both needs raster and it's ready to draw. Hence, we |
- // have to iterate the queue to check whether the required tiles are ready to |
- // draw. |
- for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) { |
- if (!raster_priority_queue->Top().tile()->draw_info().IsReadyToDraw()) |
- return false; |
- } |
- |
-#if DCHECK_IS_ON() |
- scoped_ptr<RasterTilePriorityQueue> all_queue( |
- client_->BuildRasterQueue(global_state_.tree_priority, type)); |
- for (; !all_queue->IsEmpty(); all_queue->Pop()) { |
- Tile* tile = all_queue->Top().tile(); |
- DCHECK_IMPLIES(tile->required_for_activation(), |
- tile->draw_info().IsReadyToDraw()); |
- } |
-#endif |
- return true; |
-} |
-bool TileManager::IsReadyToActivate() const { |
- TRACE_EVENT0("cc", "TileManager::IsReadyToActivate"); |
- return AreRequiredTilesReadyToDraw( |
- RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION); |
-} |
- |
-bool TileManager::IsReadyToDraw() const { |
- TRACE_EVENT0("cc", "TileManager::IsReadyToDraw"); |
- return AreRequiredTilesReadyToDraw( |
- RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW); |
-} |
- |
-void TileManager::NotifyReadyToActivate() { |
- TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate"); |
- if (did_notify_ready_to_activate_) |
- return; |
- client_->NotifyReadyToActivate(); |
- did_notify_ready_to_activate_ = true; |
-} |
- |
-void TileManager::NotifyReadyToDraw() { |
- TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw"); |
- if (did_notify_ready_to_draw_) |
- return; |
- client_->NotifyReadyToDraw(); |
- did_notify_ready_to_draw_ = true; |
-} |
- |
-void TileManager::CheckIfReadyToActivate() { |
- TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate"); |
- |
- tile_task_runner_->CheckForCompletedTasks(); |
- did_check_for_completed_tasks_since_last_schedule_tasks_ = true; |
- |
- if (did_notify_ready_to_activate_) |
- return; |
- if (!IsReadyToActivate()) |
- return; |
- |
- NotifyReadyToActivate(); |
-} |
- |
-void TileManager::CheckIfReadyToDraw() { |
- TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw"); |
- |
- tile_task_runner_->CheckForCompletedTasks(); |
- did_check_for_completed_tasks_since_last_schedule_tasks_ = true; |
- |
- if (did_notify_ready_to_draw_) |
- return; |
- if (!IsReadyToDraw()) |
- return; |
- |
- NotifyReadyToDraw(); |
-} |
- |
-void TileManager::CheckIfMoreTilesNeedToBePrepared() { |
- tile_task_runner_->CheckForCompletedTasks(); |
- did_check_for_completed_tasks_since_last_schedule_tasks_ = true; |
- |
- // When OOM, keep re-assigning memory until we reach a steady state |
- // where top-priority tiles are initialized. |
- PrioritizedTileVector tiles_that_need_to_be_rasterized; |
- scoped_ptr<RasterTilePriorityQueue> raster_priority_queue( |
- client_->BuildRasterQueue(global_state_.tree_priority, |
- RasterTilePriorityQueue::Type::ALL)); |
- AssignGpuMemoryToTiles(raster_priority_queue.get(), |
- scheduled_raster_task_limit_, |
- &tiles_that_need_to_be_rasterized); |
- |
- // Inform the client that will likely require a draw if the highest priority |
- // tile that will be rasterized is required for draw. |
- client_->SetIsLikelyToRequireADraw( |
- !tiles_that_need_to_be_rasterized.empty() && |
- tiles_that_need_to_be_rasterized.front().tile()->required_for_draw()); |
- |
- // |tiles_that_need_to_be_rasterized| will be empty when we reach a |
- // steady memory state. Keep scheduling tasks until we reach this state. |
- if (!tiles_that_need_to_be_rasterized.empty()) { |
- ScheduleTasks(tiles_that_need_to_be_rasterized); |
- return; |
- } |
- |
- FreeResourcesForReleasedTiles(); |
- |
- resource_pool_->ReduceResourceUsage(); |
- |
- // We don't reserve memory for required-for-activation tiles during |
- // accelerated gestures, so we just postpone activation when we don't |
- // have these tiles, and activate after the accelerated gesture. |
- // Likewise if we don't allow any tiles (as is the case when we're |
- // invisible), if we have tiles that aren't ready, then we shouldn't |
- // activate as activation can cause checkerboards. |
- bool wait_for_all_required_tiles = |
- global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY || |
- global_state_.memory_limit_policy == ALLOW_NOTHING; |
- |
- // Mark any required-for-activation tiles that have not been been assigned |
- // memory after reaching a steady memory state as OOM. This ensures that we |
- // activate even when OOM. Note that we can't reuse the queue we used for |
- // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have |
- // evicted some tiles that would not be picked up by the old raster queue. |
- scoped_ptr<RasterTilePriorityQueue> required_for_activation_queue( |
- client_->BuildRasterQueue( |
- global_state_.tree_priority, |
- RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION)); |
- |
- // If we have tiles left to raster for activation, and we don't allow |
- // activating without them, then skip activation and return early. |
- if (!required_for_activation_queue->IsEmpty() && wait_for_all_required_tiles) |
- return; |
- |
- // Mark required tiles as OOM so that we can activate without them. |
- for (; !required_for_activation_queue->IsEmpty(); |
- required_for_activation_queue->Pop()) { |
- Tile* tile = required_for_activation_queue->Top().tile(); |
- tile->draw_info().set_oom(); |
- client_->NotifyTileStateChanged(tile); |
- } |
- |
- DCHECK(IsReadyToActivate()); |
- ready_to_activate_check_notifier_.Schedule(); |
-} |
- |
-TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) { |
-} |
- |
-TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes, int resource_count) |
- : memory_bytes_(memory_bytes), resource_count_(resource_count) { |
-} |
- |
-// static |
-TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig( |
- const gfx::Size& size, |
- ResourceFormat format) { |
- return MemoryUsage(Resource::MemorySizeBytes(size, format), 1); |
-} |
- |
-// static |
-TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) { |
- const TileDrawInfo& draw_info = tile->draw_info(); |
- if (draw_info.resource_) { |
- return MemoryUsage::FromConfig(draw_info.resource_->size(), |
- draw_info.resource_->format()); |
- } |
- return MemoryUsage(); |
-} |
- |
-TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=( |
- const MemoryUsage& other) { |
- memory_bytes_ += other.memory_bytes_; |
- resource_count_ += other.resource_count_; |
- return *this; |
-} |
- |
-TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=( |
- const MemoryUsage& other) { |
- memory_bytes_ -= other.memory_bytes_; |
- resource_count_ -= other.resource_count_; |
- return *this; |
-} |
- |
-TileManager::MemoryUsage TileManager::MemoryUsage::operator-( |
- const MemoryUsage& other) { |
- MemoryUsage result = *this; |
- result -= other; |
- return result; |
-} |
- |
-bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const { |
- return memory_bytes_ > limit.memory_bytes_ || |
- resource_count_ > limit.resource_count_; |
-} |
- |
-} // namespace cc |