Home | History | Annotate | Download | only in resources
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "cc/resources/resource_pool.h"
      6 
      7 #include "cc/resources/resource_provider.h"
      8 #include "cc/resources/scoped_resource.h"
      9 
     10 namespace cc {
     11 
     12 ResourcePool::ResourcePool(ResourceProvider* resource_provider,
     13                            GLenum target,
     14                            ResourceFormat format)
     15     : resource_provider_(resource_provider),
     16       target_(target),
     17       format_(format),
     18       max_memory_usage_bytes_(0),
     19       max_unused_memory_usage_bytes_(0),
     20       max_resource_count_(0),
     21       memory_usage_bytes_(0),
     22       unused_memory_usage_bytes_(0),
     23       resource_count_(0) {
     24 }
     25 
     26 ResourcePool::~ResourcePool() {
     27   while (!busy_resources_.empty()) {
     28     DidFinishUsingResource(busy_resources_.front());
     29     busy_resources_.pop_front();
     30   }
     31 
     32   SetResourceUsageLimits(0, 0, 0);
     33   DCHECK_EQ(0u, unused_resources_.size());
     34   DCHECK_EQ(0u, memory_usage_bytes_);
     35   DCHECK_EQ(0u, unused_memory_usage_bytes_);
     36   DCHECK_EQ(0u, resource_count_);
     37 }
     38 
     39 scoped_ptr<ScopedResource> ResourcePool::AcquireResource(gfx::Size size) {
     40   for (ResourceList::iterator it = unused_resources_.begin();
     41        it != unused_resources_.end(); ++it) {
     42     ScopedResource* resource = *it;
     43     DCHECK(resource_provider_->CanLockForWrite(resource->id()));
     44 
     45     if (resource->size() != size)
     46       continue;
     47 
     48     unused_resources_.erase(it);
     49     unused_memory_usage_bytes_ -= resource->bytes();
     50     return make_scoped_ptr(resource);
     51   }
     52 
     53   // Create new resource.
     54   scoped_ptr<ScopedResource> resource =
     55       ScopedResource::Create(resource_provider_);
     56   resource->AllocateManaged(size, target_, format_);
     57 
     58   // Extend all read locks on all resources until the resource is
     59   // finished being used, such that we know when resources are
     60   // truly safe to recycle.
     61   resource_provider_->EnableReadLockFences(resource->id(), true);
     62 
     63   memory_usage_bytes_ += resource->bytes();
     64   ++resource_count_;
     65   return resource.Pass();
     66 }
     67 
     68 void ResourcePool::ReleaseResource(scoped_ptr<ScopedResource> resource) {
     69   busy_resources_.push_back(resource.release());
     70 }
     71 
     72 void ResourcePool::SetResourceUsageLimits(
     73     size_t max_memory_usage_bytes,
     74     size_t max_unused_memory_usage_bytes,
     75     size_t max_resource_count) {
     76   max_memory_usage_bytes_ = max_memory_usage_bytes;
     77   max_unused_memory_usage_bytes_ = max_unused_memory_usage_bytes;
     78   max_resource_count_ = max_resource_count;
     79 
     80   ReduceResourceUsage();
     81 }
     82 
     83 void ResourcePool::ReduceResourceUsage() {
     84   while (!unused_resources_.empty()) {
     85     if (!ResourceUsageTooHigh())
     86       break;
     87 
     88     // LRU eviction pattern. Most recently used might be blocked by
     89     // a read lock fence but it's still better to evict the least
     90     // recently used as it prevents a resource that is hard to reuse
     91     // because of unique size from being kept around. Resources that
     92     // can't be locked for write might also not be truly free-able.
     93     // We can free the resource here but it doesn't mean that the
     94     // memory is necessarily returned to the OS.
     95     ScopedResource* resource = unused_resources_.front();
     96     unused_resources_.pop_front();
     97     memory_usage_bytes_ -= resource->bytes();
     98     unused_memory_usage_bytes_ -= resource->bytes();
     99     --resource_count_;
    100     delete resource;
    101   }
    102 }
    103 
    104 bool ResourcePool::ResourceUsageTooHigh() {
    105   if (resource_count_ > max_resource_count_)
    106     return true;
    107   if (memory_usage_bytes_ > max_memory_usage_bytes_)
    108     return true;
    109   if (unused_memory_usage_bytes_ > max_unused_memory_usage_bytes_)
    110     return true;
    111   return false;
    112 }
    113 
    114 void ResourcePool::CheckBusyResources() {
    115   ResourceList::iterator it = busy_resources_.begin();
    116 
    117   while (it != busy_resources_.end()) {
    118     ScopedResource* resource = *it;
    119 
    120     if (resource_provider_->CanLockForWrite(resource->id())) {
    121       DidFinishUsingResource(resource);
    122       it = busy_resources_.erase(it);
    123     } else {
    124       ++it;
    125     }
    126   }
    127 }
    128 
    129 void ResourcePool::DidFinishUsingResource(ScopedResource* resource) {
    130   unused_memory_usage_bytes_ += resource->bytes();
    131   unused_resources_.push_back(resource);
    132 }
    133 
    134 }  // namespace cc
    135