12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "cc/resources/resource_pool.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "cc/resources/resource_provider.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace cc {
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourcePool::Resource::Resource(cc::ResourceProvider* resource_provider,
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                 gfx::Size size,
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 GLenum format)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : cc::Resource(resource_provider->CreateManagedResource(
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       size,
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       format,
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       ResourceProvider::TextureUsageAny),
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   size,
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   format),
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource_provider_(resource_provider) {
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(id());
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourcePool::Resource::~Resource() {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(id());
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(resource_provider_);
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  resource_provider_->DeleteResource(id());
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourcePool::ResourcePool(ResourceProvider* resource_provider)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : resource_provider_(resource_provider),
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      max_memory_usage_bytes_(0),
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      max_unused_memory_usage_bytes_(0),
34f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)      max_resource_count_(0),
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      memory_usage_bytes_(0),
36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      unused_memory_usage_bytes_(0),
37f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)      resource_count_(0) {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourcePool::~ResourcePool() {
41f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)  SetResourceUsageLimits(0, 0, 0);
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<ResourcePool::Resource> ResourcePool::AcquireResource(
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    gfx::Size size, GLenum format) {
46f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)  for (ResourceList::iterator it = unused_resources_.begin();
47f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)       it != unused_resources_.end(); ++it) {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Resource* resource = *it;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(epenner): It would be nice to DCHECK that this
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // doesn't happen two frames in a row for any resource
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // in this pool.
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!resource_provider_->CanLockForWrite(resource->id()))
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (resource->size() != size)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (resource->format() != format)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
61f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)    unused_resources_.erase(it);
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    unused_memory_usage_bytes_ -= resource->bytes();
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return make_scoped_ptr(resource);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create new resource.
67f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)  Resource* resource = new Resource(resource_provider_, size, format);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Extend all read locks on all resources until the resource is
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // finished being used, such that we know when resources are
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // truly safe to recycle.
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  resource_provider_->EnableReadLockFences(resource->id(), true);
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  memory_usage_bytes_ += resource->bytes();
75f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)  ++resource_count_;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return make_scoped_ptr(resource);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourcePool::ReleaseResource(
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ResourcePool::Resource> resource) {
81f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)  if (ResourceUsageTooHigh()) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    memory_usage_bytes_ -= resource->bytes();
83f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)    --resource_count_;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  unused_memory_usage_bytes_ += resource->bytes();
88f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)  unused_resources_.push_back(resource.release());
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
91f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)void ResourcePool::SetResourceUsageLimits(
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size_t max_memory_usage_bytes,
93a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    size_t max_unused_memory_usage_bytes,
94f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)    size_t max_resource_count) {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  max_memory_usage_bytes_ = max_memory_usage_bytes;
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  max_unused_memory_usage_bytes_ = max_unused_memory_usage_bytes;
97f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)  max_resource_count_ = max_resource_count;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
99f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)  ReduceResourceUsage();
100f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)}
101f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)
102f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)void ResourcePool::ReduceResourceUsage() {
103f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)  while (!unused_resources_.empty()) {
104f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)    if (!ResourceUsageTooHigh())
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // MRU eviction pattern as least recently used is less likely to
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // be blocked by read lock fence.
109f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)    Resource* resource = unused_resources_.back();
110f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)    unused_resources_.pop_back();
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    memory_usage_bytes_ -= resource->bytes();
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    unused_memory_usage_bytes_ -= resource->bytes();
113f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)    --resource_count_;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete resource;
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
118f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)bool ResourcePool::ResourceUsageTooHigh() {
119f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)  if (resource_count_ > max_resource_count_)
120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return true;
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (memory_usage_bytes_ > max_memory_usage_bytes_)
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (unused_memory_usage_bytes_ > max_unused_memory_usage_bytes_)
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return false;
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace cc
129