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 ResourcePool::~ResourcePool() { 26 while (!busy_resources_.empty()) { 27 DidFinishUsingResource(busy_resources_.front()); 28 busy_resources_.pop_front(); 29 } 30 31 SetResourceUsageLimits(0, 0, 0); 32 DCHECK_EQ(0u, unused_resources_.size()); 33 DCHECK_EQ(0u, memory_usage_bytes_); 34 DCHECK_EQ(0u, unused_memory_usage_bytes_); 35 DCHECK_EQ(0u, resource_count_); 36 } 37 38 scoped_ptr<ScopedResource> ResourcePool::AcquireResource( 39 const gfx::Size& size) { 40 for (ResourceList::iterator it = unused_resources_.begin(); 41 it != unused_resources_.end(); 42 ++it) { 43 ScopedResource* resource = *it; 44 DCHECK(resource_provider_->CanLockForWrite(resource->id())); 45 46 if (resource->size() != size) 47 continue; 48 49 unused_resources_.erase(it); 50 unused_memory_usage_bytes_ -= resource->bytes(); 51 return make_scoped_ptr(resource); 52 } 53 54 scoped_ptr<ScopedResource> resource = 55 ScopedResource::Create(resource_provider_); 56 resource->AllocateManaged(size, target_, format_); 57 58 memory_usage_bytes_ += resource->bytes(); 59 ++resource_count_; 60 return resource.Pass(); 61 } 62 63 void ResourcePool::ReleaseResource(scoped_ptr<ScopedResource> resource) { 64 busy_resources_.push_back(resource.release()); 65 } 66 67 void ResourcePool::SetResourceUsageLimits(size_t max_memory_usage_bytes, 68 size_t max_unused_memory_usage_bytes, 69 size_t max_resource_count) { 70 max_memory_usage_bytes_ = max_memory_usage_bytes; 71 max_unused_memory_usage_bytes_ = max_unused_memory_usage_bytes; 72 max_resource_count_ = max_resource_count; 73 74 ReduceResourceUsage(); 75 } 76 77 void ResourcePool::ReduceResourceUsage() { 78 while (!unused_resources_.empty()) { 79 if (!ResourceUsageTooHigh()) 80 break; 81 82 // LRU eviction pattern. Most recently used might be blocked by 83 // a read lock fence but it's still better to evict the least 84 // recently used as it prevents a resource that is hard to reuse 85 // because of unique size from being kept around. Resources that 86 // can't be locked for write might also not be truly free-able. 87 // We can free the resource here but it doesn't mean that the 88 // memory is necessarily returned to the OS. 89 ScopedResource* resource = unused_resources_.front(); 90 unused_resources_.pop_front(); 91 memory_usage_bytes_ -= resource->bytes(); 92 unused_memory_usage_bytes_ -= resource->bytes(); 93 --resource_count_; 94 delete resource; 95 } 96 } 97 98 bool ResourcePool::ResourceUsageTooHigh() { 99 if (resource_count_ > max_resource_count_) 100 return true; 101 if (memory_usage_bytes_ > max_memory_usage_bytes_) 102 return true; 103 if (unused_memory_usage_bytes_ > max_unused_memory_usage_bytes_) 104 return true; 105 return false; 106 } 107 108 void ResourcePool::CheckBusyResources() { 109 ResourceList::iterator it = busy_resources_.begin(); 110 111 while (it != busy_resources_.end()) { 112 ScopedResource* resource = *it; 113 114 if (resource_provider_->CanLockForWrite(resource->id())) { 115 DidFinishUsingResource(resource); 116 it = busy_resources_.erase(it); 117 } else { 118 ++it; 119 } 120 } 121 } 122 123 void ResourcePool::DidFinishUsingResource(ScopedResource* resource) { 124 unused_memory_usage_bytes_ += resource->bytes(); 125 unused_resources_.push_back(resource); 126 } 127 128 } // namespace cc 129