Mac Overlays: Make ImageTransportSurfaceOverlayMac observe GPU switches
[chromium-blink-merge.git] / cc / resources / resource_pool.cc
blobcdcaa4dbe47ad9d89c617f36eee7f5cbd3cb0ba5
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(), resource->id());
28 std::string dump_name =
29 base::StringPrintf("cc/tile_memory/resource_provider_%d/resource_%d",
30 resource_provider->tracing_id(), resource->id());
31 base::trace_event::MemoryAllocatorDump* dump =
32 pmd->CreateAllocatorDump(dump_name);
34 pmd->AddSuballocation(dump->guid(), parent_node);
36 uint64_t total_bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>(
37 resource->size(), resource->format());
38 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
39 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
40 total_bytes);
41 dump->AddScalar("free_size",
42 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
43 is_free ? total_bytes : 0);
45 ResourcePool::ResourcePool(ResourceProvider* resource_provider)
46 : resource_provider_(resource_provider),
47 target_(0),
48 max_memory_usage_bytes_(0),
49 max_unused_memory_usage_bytes_(0),
50 max_resource_count_(0),
51 memory_usage_bytes_(0),
52 unused_memory_usage_bytes_(0),
53 resource_count_(0) {
54 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
55 this, base::ThreadTaskRunnerHandle::Get());
58 ResourcePool::ResourcePool(ResourceProvider* resource_provider, GLenum target)
59 : resource_provider_(resource_provider),
60 target_(target),
61 max_memory_usage_bytes_(0),
62 max_unused_memory_usage_bytes_(0),
63 max_resource_count_(0),
64 memory_usage_bytes_(0),
65 unused_memory_usage_bytes_(0),
66 resource_count_(0) {
67 DCHECK_NE(0u, target);
68 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
69 this, base::ThreadTaskRunnerHandle::Get());
72 ResourcePool::~ResourcePool() {
73 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
74 this);
75 while (!busy_resources_.empty()) {
76 auto const& front = busy_resources_.front();
77 DidFinishUsingResource(front.resource, front.content_id);
78 busy_resources_.pop_front();
81 SetResourceUsageLimits(0, 0, 0);
82 DCHECK_EQ(0u, unused_resources_.size());
83 DCHECK_EQ(0u, memory_usage_bytes_);
84 DCHECK_EQ(0u, unused_memory_usage_bytes_);
85 DCHECK_EQ(0u, resource_count_);
88 scoped_ptr<ScopedResource> ResourcePool::AcquireResource(
89 const gfx::Size& size, ResourceFormat format) {
90 for (ResourceList::iterator it = unused_resources_.begin();
91 it != unused_resources_.end();
92 ++it) {
93 ScopedResource* resource = it->resource;
94 DCHECK(resource_provider_->CanLockForWrite(resource->id()));
96 if (resource->format() != format)
97 continue;
98 if (resource->size() != size)
99 continue;
101 unused_resources_.erase(it);
102 unused_memory_usage_bytes_ -=
103 ResourceUtil::UncheckedSizeInBytes<size_t>(size, format);
104 return make_scoped_ptr(resource);
107 scoped_ptr<ScopedResource> resource =
108 ScopedResource::Create(resource_provider_);
109 GLenum target =
110 target_ ? target_ : resource_provider_->GetImageTextureTarget(format);
111 resource->AllocateManaged(size, target, format);
113 DCHECK(ResourceUtil::VerifySizeInBytes<size_t>(resource->size(),
114 resource->format()));
115 memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
116 resource->size(), resource->format());
117 ++resource_count_;
118 return resource.Pass();
121 scoped_ptr<ScopedResource> ResourcePool::TryAcquireResourceWithContentId(
122 uint64_t content_id) {
123 DCHECK(content_id);
125 auto it = std::find_if(unused_resources_.begin(), unused_resources_.end(),
126 [content_id](const PoolResource& pool_resource) {
127 return pool_resource.content_id == content_id;
129 if (it == unused_resources_.end())
130 return nullptr;
132 ScopedResource* resource = it->resource;
133 DCHECK(resource_provider_->CanLockForWrite(resource->id()));
135 unused_resources_.erase(it);
136 unused_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
137 resource->size(), resource->format());
138 return make_scoped_ptr(resource);
141 void ResourcePool::ReleaseResource(scoped_ptr<ScopedResource> resource,
142 uint64_t content_id) {
143 busy_resources_.push_back(PoolResource(resource.release(), content_id));
146 void ResourcePool::SetResourceUsageLimits(size_t max_memory_usage_bytes,
147 size_t max_unused_memory_usage_bytes,
148 size_t max_resource_count) {
149 max_memory_usage_bytes_ = max_memory_usage_bytes;
150 max_unused_memory_usage_bytes_ = max_unused_memory_usage_bytes;
151 max_resource_count_ = max_resource_count;
153 ReduceResourceUsage();
156 void ResourcePool::ReduceResourceUsage() {
157 while (!unused_resources_.empty()) {
158 if (!ResourceUsageTooHigh())
159 break;
161 // LRU eviction pattern. Most recently used might be blocked by
162 // a read lock fence but it's still better to evict the least
163 // recently used as it prevents a resource that is hard to reuse
164 // because of unique size from being kept around. Resources that
165 // can't be locked for write might also not be truly free-able.
166 // We can free the resource here but it doesn't mean that the
167 // memory is necessarily returned to the OS.
168 ScopedResource* resource = unused_resources_.front().resource;
169 unused_resources_.pop_front();
170 unused_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
171 resource->size(), resource->format());
172 DeleteResource(resource);
176 bool ResourcePool::ResourceUsageTooHigh() {
177 if (resource_count_ > max_resource_count_)
178 return true;
179 if (memory_usage_bytes_ > max_memory_usage_bytes_)
180 return true;
181 if (unused_memory_usage_bytes_ > max_unused_memory_usage_bytes_)
182 return true;
183 return false;
186 void ResourcePool::DeleteResource(ScopedResource* resource) {
187 size_t resource_bytes = ResourceUtil::UncheckedSizeInBytes<size_t>(
188 resource->size(), resource->format());
189 memory_usage_bytes_ -= resource_bytes;
190 --resource_count_;
191 delete resource;
194 void ResourcePool::CheckBusyResources(bool wait_if_needed) {
195 ResourceList::iterator it = busy_resources_.begin();
197 while (it != busy_resources_.end()) {
198 ScopedResource* resource = it->resource;
200 if (wait_if_needed)
201 resource_provider_->WaitReadLockIfNeeded(resource->id());
203 if (resource_provider_->CanLockForWrite(resource->id())) {
204 DidFinishUsingResource(resource, it->content_id);
205 it = busy_resources_.erase(it);
206 } else if (resource_provider_->IsLost(resource->id())) {
207 // Remove lost resources from pool.
208 DeleteResource(resource);
209 it = busy_resources_.erase(it);
210 } else {
211 ++it;
216 void ResourcePool::DidFinishUsingResource(ScopedResource* resource,
217 uint64_t content_id) {
218 unused_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
219 resource->size(), resource->format());
220 unused_resources_.push_back(PoolResource(resource, content_id));
223 bool ResourcePool::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
224 base::trace_event::ProcessMemoryDump* pmd) {
225 for (const auto& resource : unused_resources_) {
226 resource.OnMemoryDump(pmd, resource_provider_, true /* is_free */);
228 for (const auto& resource : busy_resources_) {
229 resource.OnMemoryDump(pmd, resource_provider_, false /* is_free */);
231 // TODO(ericrk): Dump vended out resources once that data is available.
232 // crbug.com/516541
233 return true;
236 } // namespace cc