Index: cc/resources/prioritized_resource_manager.cc |
diff --git a/cc/resources/prioritized_resource_manager.cc b/cc/resources/prioritized_resource_manager.cc |
deleted file mode 100644 |
index 236377b851184d66308d90e38ecec5b550ae153a..0000000000000000000000000000000000000000 |
--- a/cc/resources/prioritized_resource_manager.cc |
+++ /dev/null |
@@ -1,547 +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/prioritized_resource_manager.h" |
- |
-#include <algorithm> |
- |
-#include "base/trace_event/trace_event.h" |
-#include "cc/resources/prioritized_resource.h" |
-#include "cc/resources/priority_calculator.h" |
-#include "cc/trees/proxy.h" |
- |
-namespace cc { |
- |
-PrioritizedResourceManager::PrioritizedResourceManager(const Proxy* proxy) |
- : max_memory_limit_bytes_(DefaultMemoryAllocationLimit()), |
- external_priority_cutoff_(PriorityCalculator::AllowEverythingCutoff()), |
- memory_use_bytes_(0), |
- memory_above_cutoff_bytes_(0), |
- max_memory_needed_bytes_(0), |
- memory_available_bytes_(0), |
- proxy_(proxy), |
- backings_tail_not_sorted_(false), |
- memory_visible_bytes_(0), |
- memory_visible_and_nearby_bytes_(0), |
- memory_visible_last_pushed_bytes_(0), |
- memory_visible_and_nearby_last_pushed_bytes_(0) {} |
- |
-PrioritizedResourceManager::~PrioritizedResourceManager() { |
- while (textures_.size() > 0) |
- UnregisterTexture(*textures_.begin()); |
- |
- UnlinkAndClearEvictedBackings(); |
- DCHECK(evicted_backings_.empty()); |
- |
- // Each remaining backing is a leaked opengl texture. There should be none. |
- DCHECK(backings_.empty()); |
-} |
- |
-size_t PrioritizedResourceManager::MemoryVisibleBytes() const { |
- DCHECK(proxy_->IsImplThread()); |
- return memory_visible_last_pushed_bytes_; |
-} |
- |
-size_t PrioritizedResourceManager::MemoryVisibleAndNearbyBytes() const { |
- DCHECK(proxy_->IsImplThread()); |
- return memory_visible_and_nearby_last_pushed_bytes_; |
-} |
- |
-void PrioritizedResourceManager::PrioritizeTextures() { |
- TRACE_EVENT0("cc", "PrioritizedResourceManager::PrioritizeTextures"); |
- DCHECK(proxy_->IsMainThread()); |
- |
- // Sorting textures in this function could be replaced by a slightly |
- // modified O(n) quick-select to partition textures rather than |
- // sort them (if performance of the sort becomes an issue). |
- |
- TextureVector& sorted_textures = temp_texture_vector_; |
- sorted_textures.clear(); |
- |
- // Copy all textures into a vector, sort them, and collect memory requirements |
- // statistics. |
- memory_visible_bytes_ = 0; |
- memory_visible_and_nearby_bytes_ = 0; |
- for (TextureSet::iterator it = textures_.begin(); it != textures_.end(); |
- ++it) { |
- PrioritizedResource* texture = (*it); |
- sorted_textures.push_back(texture); |
- if (PriorityCalculator::priority_is_higher( |
- texture->request_priority(), |
- PriorityCalculator::AllowVisibleOnlyCutoff())) |
- memory_visible_bytes_ += texture->bytes(); |
- if (PriorityCalculator::priority_is_higher( |
- texture->request_priority(), |
- PriorityCalculator::AllowVisibleAndNearbyCutoff())) |
- memory_visible_and_nearby_bytes_ += texture->bytes(); |
- } |
- std::sort(sorted_textures.begin(), sorted_textures.end(), CompareTextures); |
- |
- // Compute a priority cutoff based on memory pressure |
- memory_available_bytes_ = max_memory_limit_bytes_; |
- priority_cutoff_ = external_priority_cutoff_; |
- size_t memory_bytes = 0; |
- for (TextureVector::iterator it = sorted_textures.begin(); |
- it != sorted_textures.end(); |
- ++it) { |
- if ((*it)->is_self_managed()) { |
- // Account for self-managed memory immediately by reducing the memory |
- // available (since it never gets acquired). |
- size_t new_memory_bytes = memory_bytes + (*it)->bytes(); |
- if (new_memory_bytes > memory_available_bytes_) { |
- priority_cutoff_ = (*it)->request_priority(); |
- memory_available_bytes_ = memory_bytes; |
- break; |
- } |
- memory_available_bytes_ -= (*it)->bytes(); |
- } else { |
- size_t new_memory_bytes = memory_bytes + (*it)->bytes(); |
- if (new_memory_bytes > memory_available_bytes_) { |
- priority_cutoff_ = (*it)->request_priority(); |
- break; |
- } |
- memory_bytes = new_memory_bytes; |
- } |
- } |
- |
- // Disallow any textures with priority below the external cutoff to have |
- // backings. |
- for (TextureVector::iterator it = sorted_textures.begin(); |
- it != sorted_textures.end(); |
- ++it) { |
- PrioritizedResource* texture = (*it); |
- if (!PriorityCalculator::priority_is_higher(texture->request_priority(), |
- external_priority_cutoff_) && |
- texture->have_backing_texture()) |
- texture->Unlink(); |
- } |
- |
- // Only allow textures if they are higher than the cutoff. All textures |
- // of the same priority are accepted or rejected together, rather than |
- // being partially allowed randomly. |
- max_memory_needed_bytes_ = 0; |
- memory_above_cutoff_bytes_ = 0; |
- for (TextureVector::iterator it = sorted_textures.begin(); |
- it != sorted_textures.end(); |
- ++it) { |
- PrioritizedResource* resource = *it; |
- bool is_above_priority_cutoff = PriorityCalculator::priority_is_higher( |
- resource->request_priority(), priority_cutoff_); |
- resource->set_above_priority_cutoff(is_above_priority_cutoff); |
- if (!resource->is_self_managed()) { |
- max_memory_needed_bytes_ += resource->bytes(); |
- if (is_above_priority_cutoff) |
- memory_above_cutoff_bytes_ += resource->bytes(); |
- } |
- } |
- sorted_textures.clear(); |
- |
- DCHECK_LE(memory_above_cutoff_bytes_, memory_available_bytes_); |
- DCHECK_LE(MemoryAboveCutoffBytes(), MaxMemoryLimitBytes()); |
-} |
- |
-void PrioritizedResourceManager::PushTexturePrioritiesToBackings() { |
- TRACE_EVENT0("cc", |
- "PrioritizedResourceManager::PushTexturePrioritiesToBackings"); |
- DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked()); |
- |
- AssertInvariants(); |
- for (BackingList::iterator it = backings_.begin(); it != backings_.end(); |
- ++it) |
- (*it)->UpdatePriority(); |
- SortBackings(); |
- AssertInvariants(); |
- |
- // Push memory requirements to the impl thread structure. |
- memory_visible_last_pushed_bytes_ = memory_visible_bytes_; |
- memory_visible_and_nearby_last_pushed_bytes_ = |
- memory_visible_and_nearby_bytes_; |
-} |
- |
-void PrioritizedResourceManager::UpdateBackingsState( |
- ResourceProvider* resource_provider) { |
- TRACE_EVENT0("cc", |
- "PrioritizedResourceManager::UpdateBackingsInDrawingImplTree"); |
- DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked()); |
- |
- AssertInvariants(); |
- for (BackingList::iterator it = backings_.begin(); it != backings_.end(); |
- ++it) { |
- PrioritizedResource::Backing* backing = (*it); |
- backing->UpdateState(resource_provider); |
- } |
- SortBackings(); |
- AssertInvariants(); |
-} |
- |
-void PrioritizedResourceManager::SortBackings() { |
- TRACE_EVENT0("cc", "PrioritizedResourceManager::SortBackings"); |
- DCHECK(proxy_->IsImplThread()); |
- |
- // Put backings in eviction/recycling order. |
- backings_.sort(CompareBackings); |
- backings_tail_not_sorted_ = false; |
-} |
- |
-void PrioritizedResourceManager::ClearPriorities() { |
- DCHECK(proxy_->IsMainThread()); |
- for (TextureSet::iterator it = textures_.begin(); it != textures_.end(); |
- ++it) { |
- // TODO(reveman): We should remove this and just set all priorities to |
- // PriorityCalculator::lowestPriority() once we have priorities for all |
- // textures (we can't currently calculate distances for off-screen |
- // textures). |
- (*it)->set_request_priority( |
- PriorityCalculator::LingeringPriority((*it)->request_priority())); |
- } |
-} |
- |
-bool PrioritizedResourceManager::RequestLate(PrioritizedResource* texture) { |
- DCHECK(proxy_->IsMainThread()); |
- |
- // This is already above cutoff, so don't double count it's memory below. |
- if (texture->is_above_priority_cutoff()) |
- return true; |
- |
- // Allow textures that have priority equal to the cutoff, but not strictly |
- // lower. |
- if (PriorityCalculator::priority_is_lower(texture->request_priority(), |
- priority_cutoff_)) |
- return false; |
- |
- // Disallow textures that do not have a priority strictly higher than the |
- // external cutoff. |
- if (!PriorityCalculator::priority_is_higher(texture->request_priority(), |
- external_priority_cutoff_)) |
- return false; |
- |
- size_t new_memory_bytes = memory_above_cutoff_bytes_ + texture->bytes(); |
- if (new_memory_bytes > memory_available_bytes_) |
- return false; |
- |
- memory_above_cutoff_bytes_ = new_memory_bytes; |
- texture->set_above_priority_cutoff(true); |
- return true; |
-} |
- |
-void PrioritizedResourceManager::AcquireBackingTextureIfNeeded( |
- PrioritizedResource* texture, |
- ResourceProvider* resource_provider) { |
- DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked()); |
- DCHECK(!texture->is_self_managed()); |
- DCHECK(texture->is_above_priority_cutoff()); |
- if (texture->backing() || !texture->is_above_priority_cutoff()) |
- return; |
- |
- // Find a backing below, by either recycling or allocating. |
- PrioritizedResource::Backing* backing = NULL; |
- |
- // First try to recycle |
- for (BackingList::iterator it = backings_.begin(); it != backings_.end(); |
- ++it) { |
- if (!(*it)->CanBeRecycledIfNotInExternalUse()) |
- break; |
- if (resource_provider->InUseByConsumer((*it)->id())) |
- continue; |
- if ((*it)->size() == texture->size() && |
- (*it)->format() == texture->format()) { |
- backing = (*it); |
- backings_.erase(it); |
- break; |
- } |
- } |
- |
- // Otherwise reduce memory and just allocate a new backing texures. |
- if (!backing) { |
- EvictBackingsToReduceMemory(memory_available_bytes_ - texture->bytes(), |
- PriorityCalculator::AllowEverythingCutoff(), |
- EVICT_ONLY_RECYCLABLE, |
- DO_NOT_UNLINK_BACKINGS, |
- resource_provider); |
- backing = |
- CreateBacking(texture->size(), texture->format(), resource_provider); |
- } |
- |
- // Move the used backing to the end of the eviction list, and note that |
- // the tail is not sorted. |
- if (backing->owner()) |
- backing->owner()->Unlink(); |
- texture->Link(backing); |
- backings_.push_back(backing); |
- backings_tail_not_sorted_ = true; |
- |
- // Update the backing's priority from its new owner. |
- backing->UpdatePriority(); |
-} |
- |
-bool PrioritizedResourceManager::EvictBackingsToReduceMemory( |
- size_t limit_bytes, |
- int priority_cutoff, |
- EvictionPolicy eviction_policy, |
- UnlinkPolicy unlink_policy, |
- ResourceProvider* resource_provider) { |
- DCHECK(proxy_->IsImplThread()); |
- if (unlink_policy == UNLINK_BACKINGS) |
- DCHECK(proxy_->IsMainThreadBlocked()); |
- if (MemoryUseBytes() <= limit_bytes && |
- PriorityCalculator::AllowEverythingCutoff() == priority_cutoff) |
- return false; |
- |
- // Destroy backings until we are below the limit, |
- // or until all backings remaining are above the cutoff. |
- bool evicted_anything = false; |
- while (backings_.size() > 0) { |
- PrioritizedResource::Backing* backing = backings_.front(); |
- if (MemoryUseBytes() <= limit_bytes && |
- PriorityCalculator::priority_is_higher( |
- backing->request_priority_at_last_priority_update(), |
- priority_cutoff)) |
- break; |
- if (eviction_policy == EVICT_ONLY_RECYCLABLE && |
- !backing->CanBeRecycledIfNotInExternalUse()) |
- break; |
- if (unlink_policy == UNLINK_BACKINGS && backing->owner()) |
- backing->owner()->Unlink(); |
- EvictFirstBackingResource(resource_provider); |
- evicted_anything = true; |
- } |
- return evicted_anything; |
-} |
- |
-void PrioritizedResourceManager::ReduceWastedMemory( |
- ResourceProvider* resource_provider) { |
- // We currently collect backings from deleted textures for later recycling. |
- // However, if we do that forever we will always use the max limit even if |
- // we really need very little memory. This should probably be solved by |
- // reducing the limit externally, but until then this just does some "clean |
- // up" of unused backing textures (any more than 10%). |
- size_t wasted_memory = 0; |
- for (BackingList::iterator it = backings_.begin(); it != backings_.end(); |
- ++it) { |
- if ((*it)->owner()) |
- break; |
- if ((*it)->in_parent_compositor()) |
- continue; |
- wasted_memory += (*it)->bytes(); |
- } |
- size_t wasted_memory_to_allow = memory_available_bytes_ / 10; |
- // If the external priority cutoff indicates that unused memory should be |
- // freed, then do not allow any memory for texture recycling. |
- if (external_priority_cutoff_ != PriorityCalculator::AllowEverythingCutoff()) |
- wasted_memory_to_allow = 0; |
- if (wasted_memory > wasted_memory_to_allow) |
- EvictBackingsToReduceMemory(MemoryUseBytes() - |
- (wasted_memory - wasted_memory_to_allow), |
- PriorityCalculator::AllowEverythingCutoff(), |
- EVICT_ONLY_RECYCLABLE, |
- DO_NOT_UNLINK_BACKINGS, |
- resource_provider); |
-} |
- |
-void PrioritizedResourceManager::ReduceMemory( |
- ResourceProvider* resource_provider) { |
- DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked()); |
- EvictBackingsToReduceMemory(memory_available_bytes_, |
- PriorityCalculator::AllowEverythingCutoff(), |
- EVICT_ANYTHING, |
- UNLINK_BACKINGS, |
- resource_provider); |
- DCHECK_LE(MemoryUseBytes(), memory_available_bytes_); |
- |
- ReduceWastedMemory(resource_provider); |
-} |
- |
-void PrioritizedResourceManager::ClearAllMemory( |
- ResourceProvider* resource_provider) { |
- DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked()); |
- if (!resource_provider) { |
- DCHECK(backings_.empty()); |
- return; |
- } |
- EvictBackingsToReduceMemory(0, |
- PriorityCalculator::AllowEverythingCutoff(), |
- EVICT_ANYTHING, |
- DO_NOT_UNLINK_BACKINGS, |
- resource_provider); |
-} |
- |
-bool PrioritizedResourceManager::ReduceMemoryOnImplThread( |
- size_t limit_bytes, |
- int priority_cutoff, |
- ResourceProvider* resource_provider) { |
- DCHECK(proxy_->IsImplThread()); |
- DCHECK(resource_provider); |
- |
- // If we are in the process of uploading a new frame then the backings at the |
- // very end of the list are not sorted by priority. Sort them before doing the |
- // eviction. |
- if (backings_tail_not_sorted_) |
- SortBackings(); |
- return EvictBackingsToReduceMemory(limit_bytes, |
- priority_cutoff, |
- EVICT_ANYTHING, |
- DO_NOT_UNLINK_BACKINGS, |
- resource_provider); |
-} |
- |
-void PrioritizedResourceManager::UnlinkAndClearEvictedBackings() { |
- DCHECK(proxy_->IsMainThread()); |
- base::AutoLock scoped_lock(evicted_backings_lock_); |
- for (BackingList::const_iterator it = evicted_backings_.begin(); |
- it != evicted_backings_.end(); |
- ++it) { |
- PrioritizedResource::Backing* backing = (*it); |
- if (backing->owner()) |
- backing->owner()->Unlink(); |
- delete backing; |
- } |
- evicted_backings_.clear(); |
-} |
- |
-bool PrioritizedResourceManager::LinkedEvictedBackingsExist() const { |
- DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked()); |
- base::AutoLock scoped_lock(evicted_backings_lock_); |
- for (BackingList::const_iterator it = evicted_backings_.begin(); |
- it != evicted_backings_.end(); |
- ++it) { |
- if ((*it)->owner()) |
- return true; |
- } |
- return false; |
-} |
- |
-void PrioritizedResourceManager::RegisterTexture(PrioritizedResource* texture) { |
- DCHECK(proxy_->IsMainThread()); |
- DCHECK(texture); |
- DCHECK(!texture->resource_manager()); |
- DCHECK(!texture->backing()); |
- DCHECK(!ContainsKey(textures_, texture)); |
- |
- texture->set_manager_internal(this); |
- textures_.insert(texture); |
-} |
- |
-void PrioritizedResourceManager::UnregisterTexture( |
- PrioritizedResource* texture) { |
- DCHECK(proxy_->IsMainThread() || |
- (proxy_->IsImplThread() && proxy_->IsMainThreadBlocked())); |
- DCHECK(texture); |
- DCHECK(ContainsKey(textures_, texture)); |
- |
- ReturnBackingTexture(texture); |
- texture->set_manager_internal(NULL); |
- textures_.erase(texture); |
- texture->set_above_priority_cutoff(false); |
-} |
- |
-void PrioritizedResourceManager::ReturnBackingTexture( |
- PrioritizedResource* texture) { |
- DCHECK(proxy_->IsMainThread() || |
- (proxy_->IsImplThread() && proxy_->IsMainThreadBlocked())); |
- if (texture->backing()) |
- texture->Unlink(); |
-} |
- |
-PrioritizedResource::Backing* PrioritizedResourceManager::CreateBacking( |
- const gfx::Size& size, |
- ResourceFormat format, |
- ResourceProvider* resource_provider) { |
- DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked()); |
- DCHECK(resource_provider); |
- ResourceProvider::ResourceId resource_id = |
- resource_provider->CreateManagedResource( |
- size, GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, |
- ResourceProvider::TEXTURE_HINT_IMMUTABLE, format); |
- PrioritizedResource::Backing* backing = new PrioritizedResource::Backing( |
- resource_id, resource_provider, size, format); |
- memory_use_bytes_ += backing->bytes(); |
- return backing; |
-} |
- |
-void PrioritizedResourceManager::EvictFirstBackingResource( |
- ResourceProvider* resource_provider) { |
- DCHECK(proxy_->IsImplThread()); |
- DCHECK(resource_provider); |
- DCHECK(!backings_.empty()); |
- PrioritizedResource::Backing* backing = backings_.front(); |
- |
- // Note that we create a backing and its resource at the same time, but we |
- // delete the backing structure and its resource in two steps. This is because |
- // we can delete the resource while the main thread is running, but we cannot |
- // unlink backings while the main thread is running. |
- backing->DeleteResource(resource_provider); |
- memory_use_bytes_ -= backing->bytes(); |
- backings_.pop_front(); |
- base::AutoLock scoped_lock(evicted_backings_lock_); |
- evicted_backings_.push_back(backing); |
-} |
- |
-void PrioritizedResourceManager::AssertInvariants() { |
-#if DCHECK_IS_ON() |
- DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked()); |
- |
- // If we hit any of these asserts, there is a bug in this class. To see |
- // where the bug is, call this function at the beginning and end of |
- // every public function. |
- |
- // Backings/textures must be doubly-linked and only to other backings/textures |
- // in this manager. |
- for (BackingList::iterator it = backings_.begin(); it != backings_.end(); |
- ++it) { |
- if ((*it)->owner()) { |
- DCHECK(ContainsKey(textures_, (*it)->owner())); |
- DCHECK((*it)->owner()->backing() == (*it)); |
- } |
- } |
- for (TextureSet::iterator it = textures_.begin(); it != textures_.end(); |
- ++it) { |
- PrioritizedResource* texture = (*it); |
- PrioritizedResource::Backing* backing = texture->backing(); |
- base::AutoLock scoped_lock(evicted_backings_lock_); |
- if (backing) { |
- if (backing->ResourceHasBeenDeleted()) { |
- DCHECK(std::find(backings_.begin(), backings_.end(), backing) == |
- backings_.end()); |
- DCHECK(std::find(evicted_backings_.begin(), |
- evicted_backings_.end(), |
- backing) != evicted_backings_.end()); |
- } else { |
- DCHECK(std::find(backings_.begin(), backings_.end(), backing) != |
- backings_.end()); |
- DCHECK(std::find(evicted_backings_.begin(), |
- evicted_backings_.end(), |
- backing) == evicted_backings_.end()); |
- } |
- DCHECK(backing->owner() == texture); |
- } |
- } |
- |
- // At all times, backings that can be evicted must always come before |
- // backings that can't be evicted in the backing texture list (otherwise |
- // ReduceMemory will not find all textures available for eviction/recycling). |
- bool reached_unrecyclable = false; |
- PrioritizedResource::Backing* previous_backing = NULL; |
- for (BackingList::iterator it = backings_.begin(); it != backings_.end(); |
- ++it) { |
- PrioritizedResource::Backing* backing = *it; |
- if (previous_backing && |
- (!backings_tail_not_sorted_ || |
- !backing->was_above_priority_cutoff_at_last_priority_update())) |
- DCHECK(CompareBackings(previous_backing, backing)); |
- if (!backing->CanBeRecycledIfNotInExternalUse()) |
- reached_unrecyclable = true; |
- if (reached_unrecyclable) |
- DCHECK(!backing->CanBeRecycledIfNotInExternalUse()); |
- else |
- DCHECK(backing->CanBeRecycledIfNotInExternalUse()); |
- previous_backing = backing; |
- } |
-#endif // DCHECK_IS_ON() |
-} |
- |
-const Proxy* PrioritizedResourceManager::ProxyForDebug() const { |
- return proxy_; |
-} |
- |
-} // namespace cc |