Roll WebRTC 9745:9761, Libjingle 9742:9761
[chromium-blink-merge.git] / cc / resources / resource_pool.cc
blob5a6654e001ba687af6621f37933e8c70a496a9d8
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.
5 #include "cc/resources/resource_pool.h"
7 #include <algorithm>
9 #include "base/format_macros.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "base/trace_event/memory_dump_manager.h"
13 #include "cc/resources/resource_provider.h"
14 #include "cc/resources/resource_util.h"
15 #include "cc/resources/scoped_resource.h"
17 namespace cc {
19 void ResourcePool::PoolResource::OnMemoryDump(
20 base::trace_event::ProcessMemoryDump* pmd,
21 const ResourceProvider* resource_provider,
22 bool is_free) const {
23 // Resource IDs are not process-unique, so log with the ResourceProvider's
24 // unique id.
25 std::string parent_node =
26 base::StringPrintf("cc/resource_memory/resource_provider_%d/resource_%d",
27 resource_provider->tracing_id(), id());
29 std::string dump_name =
30 base::StringPrintf("cc/tile_memory/resource_provider_%d/resource_%d",
31 resource_provider->tracing_id(), id());
32 base::trace_event::MemoryAllocatorDump* dump =
33 pmd->CreateAllocatorDump(dump_name);
35 pmd->AddSuballocation(dump->guid(), parent_node);
37 uint64_t total_bytes =
38 ResourceUtil::UncheckedSizeInBytesAligned<size_t>(size(), format());
39 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
40 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
41 total_bytes);
43 if (is_free) {
44 dump->AddScalar("free_size",
45 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
46 total_bytes);
49 ResourcePool::ResourcePool(ResourceProvider* resource_provider)
50 : resource_provider_(resource_provider),
51 target_(0),
52 max_memory_usage_bytes_(0),
53 max_unused_memory_usage_bytes_(0),
54 max_resource_count_(0),
55 memory_usage_bytes_(0),
56 unused_memory_usage_bytes_(0),
57 resource_count_(0) {
58 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
59 this, base::ThreadTaskRunnerHandle::Get());
62 ResourcePool::ResourcePool(ResourceProvider* resource_provider, GLenum target)
63 : resource_provider_(resource_provider),
64 target_(target),
65 max_memory_usage_bytes_(0),
66 max_unused_memory_usage_bytes_(0),
67 max_resource_count_(0),
68 memory_usage_bytes_(0),
69 unused_memory_usage_bytes_(0),
70 resource_count_(0) {
71 DCHECK_NE(0u, target);
72 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
73 this, base::ThreadTaskRunnerHandle::Get());
76 ResourcePool::~ResourcePool() {
77 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
78 this);
80 DCHECK_EQ(0u, in_use_resources_.size());
82 while (!busy_resources_.empty()) {
83 DidFinishUsingResource(busy_resources_.take_front());
86 SetResourceUsageLimits(0, 0, 0);
87 DCHECK_EQ(0u, unused_resources_.size());
88 DCHECK_EQ(0u, memory_usage_bytes_);
89 DCHECK_EQ(0u, unused_memory_usage_bytes_);
90 DCHECK_EQ(0u, resource_count_);
93 Resource* ResourcePool::AcquireResource(const gfx::Size& size,
94 ResourceFormat format) {
95 for (ResourceDeque::iterator it = unused_resources_.begin();
96 it != unused_resources_.end(); ++it) {
97 ScopedResource* resource = *it;
98 DCHECK(resource_provider_->CanLockForWrite(resource->id()));
100 if (resource->format() != format)
101 continue;
102 if (resource->size() != size)
103 continue;
105 // Transfer resource to |in_use_resources_|.
106 in_use_resources_.set(resource->id(), unused_resources_.take(it));
108 unused_memory_usage_bytes_ -=
109 ResourceUtil::UncheckedSizeInBytes<size_t>(size, format);
110 return resource;
113 scoped_ptr<PoolResource> pool_resource =
114 PoolResource::Create(resource_provider_);
115 GLenum target =
116 target_ ? target_ : resource_provider_->GetImageTextureTarget(format);
117 pool_resource->AllocateManaged(size, target, format);
119 DCHECK(ResourceUtil::VerifySizeInBytes<size_t>(pool_resource->size(),
120 pool_resource->format()));
121 memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
122 pool_resource->size(), pool_resource->format());
123 ++resource_count_;
125 Resource* resource = pool_resource.get();
126 in_use_resources_.set(resource->id(), pool_resource.Pass());
127 return resource;
130 Resource* ResourcePool::TryAcquireResourceWithContentId(uint64_t content_id) {
131 DCHECK(content_id);
133 auto it = std::find_if(unused_resources_.begin(), unused_resources_.end(),
134 [content_id](const PoolResource* pool_resource) {
135 return pool_resource->content_id() == content_id;
137 if (it == unused_resources_.end())
138 return nullptr;
140 Resource* resource = *it;
141 DCHECK(resource_provider_->CanLockForWrite(resource->id()));
143 // Transfer resource to |in_use_resources_|.
144 in_use_resources_.set(resource->id(), unused_resources_.take(it));
146 unused_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
147 resource->size(), resource->format());
148 return resource;
151 void ResourcePool::ReleaseResource(Resource* resource, uint64_t content_id) {
152 auto it = in_use_resources_.find(resource->id());
153 DCHECK(it != in_use_resources_.end());
155 PoolResource* pool_resource = it->second;
156 pool_resource->set_content_id(content_id);
158 // Transfer resource to |busy_resources_|.
159 busy_resources_.push_back(in_use_resources_.take_and_erase(it));
162 void ResourcePool::SetResourceUsageLimits(size_t max_memory_usage_bytes,
163 size_t max_unused_memory_usage_bytes,
164 size_t max_resource_count) {
165 max_memory_usage_bytes_ = max_memory_usage_bytes;
166 max_unused_memory_usage_bytes_ = max_unused_memory_usage_bytes;
167 max_resource_count_ = max_resource_count;
169 ReduceResourceUsage();
172 void ResourcePool::ReduceResourceUsage() {
173 while (!unused_resources_.empty()) {
174 if (!ResourceUsageTooHigh())
175 break;
177 // LRU eviction pattern. Most recently used might be blocked by
178 // a read lock fence but it's still better to evict the least
179 // recently used as it prevents a resource that is hard to reuse
180 // because of unique size from being kept around. Resources that
181 // can't be locked for write might also not be truly free-able.
182 // We can free the resource here but it doesn't mean that the
183 // memory is necessarily returned to the OS.
184 scoped_ptr<PoolResource> resource = unused_resources_.take_front();
185 unused_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
186 resource->size(), resource->format());
187 DeleteResource(resource.Pass());
191 bool ResourcePool::ResourceUsageTooHigh() {
192 if (resource_count_ > max_resource_count_)
193 return true;
194 if (memory_usage_bytes_ > max_memory_usage_bytes_)
195 return true;
196 if (unused_memory_usage_bytes_ > max_unused_memory_usage_bytes_)
197 return true;
198 return false;
201 void ResourcePool::DeleteResource(scoped_ptr<PoolResource> resource) {
202 size_t resource_bytes = ResourceUtil::UncheckedSizeInBytes<size_t>(
203 resource->size(), resource->format());
204 memory_usage_bytes_ -= resource_bytes;
205 --resource_count_;
208 void ResourcePool::CheckBusyResources() {
209 for (size_t i = 0; i < busy_resources_.size();) {
210 ResourceDeque::iterator it(busy_resources_.begin() + i);
211 PoolResource* resource = *it;
213 if (resource_provider_->CanLockForWrite(resource->id())) {
214 DidFinishUsingResource(busy_resources_.take(it));
215 } else if (resource_provider_->IsLost(resource->id())) {
216 // Remove lost resources from pool.
217 DeleteResource(busy_resources_.take(it));
218 } else {
219 ++i;
224 void ResourcePool::DidFinishUsingResource(scoped_ptr<PoolResource> resource) {
225 unused_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
226 resource->size(), resource->format());
227 unused_resources_.push_back(resource.Pass());
230 bool ResourcePool::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
231 base::trace_event::ProcessMemoryDump* pmd) {
232 for (const auto& resource : unused_resources_) {
233 resource->OnMemoryDump(pmd, resource_provider_, true /* is_free */);
235 for (const auto& resource : busy_resources_) {
236 resource->OnMemoryDump(pmd, resource_provider_, false /* is_free */);
238 for (const auto& entry : in_use_resources_) {
239 entry.second->OnMemoryDump(pmd, resource_provider_, false /* is_free */);
241 return true;
244 } // namespace cc