| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/resources/resource_pool.h" | 5 #include "cc/resources/resource_pool.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 11 #include "base/thread_task_runner_handle.h" | 11 #include "base/thread_task_runner_handle.h" |
| 12 #include "base/trace_event/memory_dump_manager.h" | 12 #include "base/trace_event/memory_dump_manager.h" |
| 13 #include "cc/base/container_util.h" |
| 13 #include "cc/resources/resource_provider.h" | 14 #include "cc/resources/resource_provider.h" |
| 14 #include "cc/resources/resource_util.h" | 15 #include "cc/resources/resource_util.h" |
| 15 #include "cc/resources/scoped_resource.h" | 16 #include "cc/resources/scoped_resource.h" |
| 16 | 17 |
| 17 namespace cc { | 18 namespace cc { |
| 18 namespace { | 19 namespace { |
| 19 | 20 |
| 20 // Delay before a resource is considered expired. | 21 // Delay before a resource is considered expired. |
| 21 const int kResourceExpirationDelayMs = 1000; | 22 const int kResourceExpirationDelayMs = 1000; |
| 22 | 23 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 this, "cc::ResourcePool", task_runner_.get()); | 73 this, "cc::ResourcePool", task_runner_.get()); |
| 73 } | 74 } |
| 74 | 75 |
| 75 ResourcePool::~ResourcePool() { | 76 ResourcePool::~ResourcePool() { |
| 76 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( | 77 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( |
| 77 this); | 78 this); |
| 78 | 79 |
| 79 DCHECK_EQ(0u, in_use_resources_.size()); | 80 DCHECK_EQ(0u, in_use_resources_.size()); |
| 80 | 81 |
| 81 while (!busy_resources_.empty()) { | 82 while (!busy_resources_.empty()) { |
| 82 DidFinishUsingResource(busy_resources_.take_back()); | 83 DidFinishUsingResource(TakeBack(&busy_resources_)); |
| 83 } | 84 } |
| 84 | 85 |
| 85 SetResourceUsageLimits(0, 0); | 86 SetResourceUsageLimits(0, 0); |
| 86 DCHECK_EQ(0u, unused_resources_.size()); | 87 DCHECK_EQ(0u, unused_resources_.size()); |
| 87 DCHECK_EQ(0u, in_use_memory_usage_bytes_); | 88 DCHECK_EQ(0u, in_use_memory_usage_bytes_); |
| 88 DCHECK_EQ(0u, total_memory_usage_bytes_); | 89 DCHECK_EQ(0u, total_memory_usage_bytes_); |
| 89 DCHECK_EQ(0u, total_resource_count_); | 90 DCHECK_EQ(0u, total_resource_count_); |
| 90 } | 91 } |
| 91 | 92 |
| 92 Resource* ResourcePool::AcquireResource(const gfx::Size& size, | 93 Resource* ResourcePool::AcquireResource(const gfx::Size& size, |
| 93 ResourceFormat format) { | 94 ResourceFormat format) { |
| 94 // Finding resources in |unused_resources_| from MRU to LRU direction, touches | 95 // Finding resources in |unused_resources_| from MRU to LRU direction, touches |
| 95 // LRU resources only if needed, which increases possibility of expiring more | 96 // LRU resources only if needed, which increases possibility of expiring more |
| 96 // LRU resources within kResourceExpirationDelayMs. | 97 // LRU resources within kResourceExpirationDelayMs. |
| 97 for (ResourceDeque::iterator it = unused_resources_.begin(); | 98 for (ResourceDeque::iterator it = unused_resources_.begin(); |
| 98 it != unused_resources_.end(); ++it) { | 99 it != unused_resources_.end(); ++it) { |
| 99 ScopedResource* resource = *it; | 100 ScopedResource* resource = it->get(); |
| 100 DCHECK(resource_provider_->CanLockForWrite(resource->id())); | 101 DCHECK(resource_provider_->CanLockForWrite(resource->id())); |
| 101 | 102 |
| 102 if (resource->format() != format) | 103 if (resource->format() != format) |
| 103 continue; | 104 continue; |
| 104 if (resource->size() != size) | 105 if (resource->size() != size) |
| 105 continue; | 106 continue; |
| 106 | 107 |
| 107 // Transfer resource to |in_use_resources_|. | 108 // Transfer resource to |in_use_resources_|. |
| 108 in_use_resources_.set(resource->id(), unused_resources_.take(it)); | 109 in_use_resources_.set(resource->id(), it->Pass()); |
| 110 unused_resources_.erase(it); |
| 109 in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>( | 111 in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>( |
| 110 resource->size(), resource->format()); | 112 resource->size(), resource->format()); |
| 111 return resource; | 113 return resource; |
| 112 } | 114 } |
| 113 | 115 |
| 114 scoped_ptr<PoolResource> pool_resource = | 116 scoped_ptr<PoolResource> pool_resource = |
| 115 PoolResource::Create(resource_provider_); | 117 PoolResource::Create(resource_provider_); |
| 116 | 118 |
| 117 if (use_image_texture_target_) { | 119 if (use_image_texture_target_) { |
| 118 pool_resource->AllocateWithImageTextureTarget(size, format); | 120 pool_resource->AllocateWithImageTextureTarget(size, format); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 130 Resource* resource = pool_resource.get(); | 132 Resource* resource = pool_resource.get(); |
| 131 in_use_resources_.set(resource->id(), pool_resource.Pass()); | 133 in_use_resources_.set(resource->id(), pool_resource.Pass()); |
| 132 in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>( | 134 in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>( |
| 133 resource->size(), resource->format()); | 135 resource->size(), resource->format()); |
| 134 return resource; | 136 return resource; |
| 135 } | 137 } |
| 136 | 138 |
| 137 Resource* ResourcePool::TryAcquireResourceWithContentId(uint64_t content_id) { | 139 Resource* ResourcePool::TryAcquireResourceWithContentId(uint64_t content_id) { |
| 138 DCHECK(content_id); | 140 DCHECK(content_id); |
| 139 | 141 |
| 140 auto it = std::find_if(unused_resources_.begin(), unused_resources_.end(), | 142 auto it = |
| 141 [content_id](const PoolResource* pool_resource) { | 143 std::find_if(unused_resources_.begin(), unused_resources_.end(), |
| 142 return pool_resource->content_id() == content_id; | 144 [content_id](const scoped_ptr<PoolResource>& pool_resource) { |
| 143 }); | 145 return pool_resource->content_id() == content_id; |
| 146 }); |
| 144 if (it == unused_resources_.end()) | 147 if (it == unused_resources_.end()) |
| 145 return nullptr; | 148 return nullptr; |
| 146 | 149 |
| 147 Resource* resource = *it; | 150 Resource* resource = it->get(); |
| 148 DCHECK(resource_provider_->CanLockForWrite(resource->id())); | 151 DCHECK(resource_provider_->CanLockForWrite(resource->id())); |
| 149 | 152 |
| 150 // Transfer resource to |in_use_resources_|. | 153 // Transfer resource to |in_use_resources_|. |
| 151 in_use_resources_.set(resource->id(), unused_resources_.take(it)); | 154 in_use_resources_.set(resource->id(), it->Pass()); |
| 155 unused_resources_.erase(it); |
| 152 in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>( | 156 in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>( |
| 153 resource->size(), resource->format()); | 157 resource->size(), resource->format()); |
| 154 return resource; | 158 return resource; |
| 155 } | 159 } |
| 156 | 160 |
| 157 void ResourcePool::ReleaseResource(Resource* resource, uint64_t content_id) { | 161 void ResourcePool::ReleaseResource(Resource* resource, uint64_t content_id) { |
| 158 auto it = in_use_resources_.find(resource->id()); | 162 auto it = in_use_resources_.find(resource->id()); |
| 159 DCHECK(it != in_use_resources_.end()); | 163 DCHECK(it != in_use_resources_.end()); |
| 160 | 164 |
| 161 PoolResource* pool_resource = it->second; | 165 PoolResource* pool_resource = it->second; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 185 if (!ResourceUsageTooHigh()) | 189 if (!ResourceUsageTooHigh()) |
| 186 break; | 190 break; |
| 187 | 191 |
| 188 // LRU eviction pattern. Most recently used might be blocked by | 192 // LRU eviction pattern. Most recently used might be blocked by |
| 189 // a read lock fence but it's still better to evict the least | 193 // a read lock fence but it's still better to evict the least |
| 190 // recently used as it prevents a resource that is hard to reuse | 194 // recently used as it prevents a resource that is hard to reuse |
| 191 // because of unique size from being kept around. Resources that | 195 // because of unique size from being kept around. Resources that |
| 192 // can't be locked for write might also not be truly free-able. | 196 // can't be locked for write might also not be truly free-able. |
| 193 // We can free the resource here but it doesn't mean that the | 197 // We can free the resource here but it doesn't mean that the |
| 194 // memory is necessarily returned to the OS. | 198 // memory is necessarily returned to the OS. |
| 195 DeleteResource(unused_resources_.take_back()); | 199 DeleteResource(TakeBack(&unused_resources_)); |
| 196 } | 200 } |
| 197 } | 201 } |
| 198 | 202 |
| 199 bool ResourcePool::ResourceUsageTooHigh() { | 203 bool ResourcePool::ResourceUsageTooHigh() { |
| 200 if (total_resource_count_ > max_resource_count_) | 204 if (total_resource_count_ > max_resource_count_) |
| 201 return true; | 205 return true; |
| 202 if (total_memory_usage_bytes_ > max_memory_usage_bytes_) | 206 if (total_memory_usage_bytes_ > max_memory_usage_bytes_) |
| 203 return true; | 207 return true; |
| 204 return false; | 208 return false; |
| 205 } | 209 } |
| 206 | 210 |
| 207 void ResourcePool::DeleteResource(scoped_ptr<PoolResource> resource) { | 211 void ResourcePool::DeleteResource(scoped_ptr<PoolResource> resource) { |
| 208 size_t resource_bytes = ResourceUtil::UncheckedSizeInBytes<size_t>( | 212 size_t resource_bytes = ResourceUtil::UncheckedSizeInBytes<size_t>( |
| 209 resource->size(), resource->format()); | 213 resource->size(), resource->format()); |
| 210 total_memory_usage_bytes_ -= resource_bytes; | 214 total_memory_usage_bytes_ -= resource_bytes; |
| 211 --total_resource_count_; | 215 --total_resource_count_; |
| 212 } | 216 } |
| 213 | 217 |
| 214 void ResourcePool::CheckBusyResources() { | 218 void ResourcePool::CheckBusyResources() { |
| 215 for (size_t i = 0; i < busy_resources_.size();) { | 219 for (size_t i = 0; i < busy_resources_.size();) { |
| 216 ResourceDeque::iterator it(busy_resources_.begin() + i); | 220 ResourceDeque::iterator it(busy_resources_.begin() + i); |
| 217 PoolResource* resource = *it; | 221 PoolResource* resource = it->get(); |
| 218 | 222 |
| 219 if (resource_provider_->CanLockForWrite(resource->id())) { | 223 if (resource_provider_->CanLockForWrite(resource->id())) { |
| 220 DidFinishUsingResource(busy_resources_.take(it)); | 224 DidFinishUsingResource(it->Pass()); |
| 225 busy_resources_.erase(it); |
| 221 } else if (resource_provider_->IsLost(resource->id())) { | 226 } else if (resource_provider_->IsLost(resource->id())) { |
| 222 // Remove lost resources from pool. | 227 // Remove lost resources from pool. |
| 223 DeleteResource(busy_resources_.take(it)); | 228 DeleteResource(it->Pass()); |
| 229 busy_resources_.erase(it); |
| 224 } else { | 230 } else { |
| 225 ++i; | 231 ++i; |
| 226 } | 232 } |
| 227 } | 233 } |
| 228 } | 234 } |
| 229 | 235 |
| 230 void ResourcePool::DidFinishUsingResource(scoped_ptr<PoolResource> resource) { | 236 void ResourcePool::DidFinishUsingResource(scoped_ptr<PoolResource> resource) { |
| 231 unused_resources_.push_front(resource.Pass()); | 237 unused_resources_.push_front(resource.Pass()); |
| 232 } | 238 } |
| 233 | 239 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 263 | 269 |
| 264 void ResourcePool::EvictResourcesNotUsedSince(base::TimeTicks time_limit) { | 270 void ResourcePool::EvictResourcesNotUsedSince(base::TimeTicks time_limit) { |
| 265 while (!unused_resources_.empty()) { | 271 while (!unused_resources_.empty()) { |
| 266 // |unused_resources_| is not strictly ordered with regards to last_usage, | 272 // |unused_resources_| is not strictly ordered with regards to last_usage, |
| 267 // as this may not exactly line up with the time a resource became non-busy. | 273 // as this may not exactly line up with the time a resource became non-busy. |
| 268 // However, this should be roughly ordered, and will only introduce slight | 274 // However, this should be roughly ordered, and will only introduce slight |
| 269 // delays in freeing expired resources. | 275 // delays in freeing expired resources. |
| 270 if (unused_resources_.back()->last_usage() > time_limit) | 276 if (unused_resources_.back()->last_usage() > time_limit) |
| 271 return; | 277 return; |
| 272 | 278 |
| 273 DeleteResource(unused_resources_.take_back()); | 279 DeleteResource(TakeBack(&unused_resources_)); |
| 274 } | 280 } |
| 275 | 281 |
| 276 // Also free busy resources older than the delay. With a sufficiently large | 282 // Also free busy resources older than the delay. With a sufficiently large |
| 277 // delay, such as the 1 second used here, any "busy" resources which have | 283 // delay, such as the 1 second used here, any "busy" resources which have |
| 278 // expired are not likely to be busy. Additionally, freeing a "busy" resource | 284 // expired are not likely to be busy. Additionally, freeing a "busy" resource |
| 279 // has no downside other than incorrect accounting. | 285 // has no downside other than incorrect accounting. |
| 280 while (!busy_resources_.empty()) { | 286 while (!busy_resources_.empty()) { |
| 281 if (busy_resources_.back()->last_usage() > time_limit) | 287 if (busy_resources_.back()->last_usage() > time_limit) |
| 282 return; | 288 return; |
| 283 | 289 |
| 284 DeleteResource(busy_resources_.take_back()); | 290 DeleteResource(TakeBack(&busy_resources_)); |
| 285 } | 291 } |
| 286 } | 292 } |
| 287 | 293 |
| 288 base::TimeTicks ResourcePool::GetUsageTimeForLRUResource() const { | 294 base::TimeTicks ResourcePool::GetUsageTimeForLRUResource() const { |
| 289 if (!unused_resources_.empty()) { | 295 if (!unused_resources_.empty()) { |
| 290 return unused_resources_.back()->last_usage(); | 296 return unused_resources_.back()->last_usage(); |
| 291 } | 297 } |
| 292 | 298 |
| 293 // This is only called when we have at least one evictable resource. | 299 // This is only called when we have at least one evictable resource. |
| 294 DCHECK(!busy_resources_.empty()); | 300 DCHECK(!busy_resources_.empty()); |
| 295 return busy_resources_.back()->last_usage(); | 301 return busy_resources_.back()->last_usage(); |
| 296 } | 302 } |
| 297 | 303 |
| 298 bool ResourcePool::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, | 304 bool ResourcePool::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, |
| 299 base::trace_event::ProcessMemoryDump* pmd) { | 305 base::trace_event::ProcessMemoryDump* pmd) { |
| 300 for (const auto& resource : unused_resources_) { | 306 for (const auto& resource : unused_resources_) { |
| 301 resource->OnMemoryDump(pmd, resource_provider_, true /* is_free */); | 307 resource->OnMemoryDump(pmd, resource_provider_, true /* is_free */); |
| 302 } | 308 } |
| 303 for (const auto& resource : busy_resources_) { | 309 for (const auto& resource : busy_resources_) { |
| 304 resource->OnMemoryDump(pmd, resource_provider_, false /* is_free */); | 310 resource->OnMemoryDump(pmd, resource_provider_, false /* is_free */); |
| 305 } | 311 } |
| 306 for (const auto& entry : in_use_resources_) { | 312 for (const auto& entry : in_use_resources_) { |
| 307 entry.second->OnMemoryDump(pmd, resource_provider_, false /* is_free */); | 313 entry.second->OnMemoryDump(pmd, resource_provider_, false /* is_free */); |
| 308 } | 314 } |
| 309 return true; | 315 return true; |
| 310 } | 316 } |
| 311 | 317 |
| 312 } // namespace cc | 318 } // namespace cc |
| OLD | NEW |