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#ifndef CC_RESOURCES_PRIORITIZED_RESOURCE_MANAGER_H_
6#define CC_RESOURCES_PRIORITIZED_RESOURCE_MANAGER_H_
7
8#include <list>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/containers/hash_tables.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/synchronization/lock.h"
15#include "cc/base/cc_export.h"
16#include "cc/resources/prioritized_resource.h"
17#include "cc/resources/priority_calculator.h"
18#include "cc/resources/resource.h"
19#include "cc/trees/proxy.h"
20#include "ui/gfx/size.h"
21
22#if defined(COMPILER_GCC)
23namespace BASE_HASH_NAMESPACE {
24template <> struct hash<cc::PrioritizedResource*> {
25  size_t operator()(cc::PrioritizedResource* ptr) const {
26    return hash<size_t>()(reinterpret_cast<size_t>(ptr));
27  }
28};
29}  // namespace BASE_HASH_NAMESPACE
30#endif  // COMPILER
31
32namespace cc {
33
34class PriorityCalculator;
35class Proxy;
36
37class CC_EXPORT PrioritizedResourceManager {
38 public:
39  static scoped_ptr<PrioritizedResourceManager> Create(const Proxy* proxy) {
40    return make_scoped_ptr(new PrioritizedResourceManager(proxy));
41  }
42  scoped_ptr<PrioritizedResource> CreateTexture(
43      const gfx::Size& size, ResourceFormat format) {
44    return make_scoped_ptr(new PrioritizedResource(this, size, format));
45  }
46  ~PrioritizedResourceManager();
47
48  typedef std::list<PrioritizedResource::Backing*> BackingList;
49
50  // TODO(epenner): (http://crbug.com/137094) This 64MB default is a straggler
51  // from the old texture manager and is just to give us a default memory
52  // allocation before we get a callback from the GPU memory manager. We
53  // should probaby either:
54  // - wait for the callback before rendering anything instead
55  // - push this into the GPU memory manager somehow.
56  static size_t DefaultMemoryAllocationLimit() { return 64 * 1024 * 1024; }
57
58  // MemoryUseBytes() describes the number of bytes used by existing allocated
59  // textures.
60  size_t MemoryUseBytes() const { return memory_use_bytes_; }
61  // MemoryAboveCutoffBytes() describes the number of bytes that
62  // would be used if all textures that are above the cutoff were allocated.
63  // MemoryUseBytes() <= MemoryAboveCutoffBytes() should always be true.
64  size_t MemoryAboveCutoffBytes() const { return memory_above_cutoff_bytes_; }
65  // MaxMemoryNeededBytes() describes the number of bytes that would be used
66  // by textures if there were no limit on memory usage.
67  size_t MaxMemoryNeededBytes() const { return max_memory_needed_bytes_; }
68  size_t MemoryForSelfManagedTextures() const {
69    return max_memory_limit_bytes_ - memory_available_bytes_;
70  }
71
72  void SetMaxMemoryLimitBytes(size_t bytes) { max_memory_limit_bytes_ = bytes; }
73  size_t MaxMemoryLimitBytes() const { return max_memory_limit_bytes_; }
74
75  // Sepecify a external priority cutoff. Only textures that have a strictly
76  // higher priority than this cutoff will be allowed.
77  void SetExternalPriorityCutoff(int priority_cutoff) {
78    external_priority_cutoff_ = priority_cutoff;
79  }
80  int ExternalPriorityCutoff() const {
81    return external_priority_cutoff_;
82  }
83
84  // Return the amount of texture memory required at particular cutoffs.
85  size_t MemoryVisibleBytes() const;
86  size_t MemoryVisibleAndNearbyBytes() const;
87
88  void PrioritizeTextures();
89  void ClearPriorities();
90
91  // Delete contents textures' backing resources until they use only
92  // limit_bytes bytes. This may be called on the impl thread while the main
93  // thread is running. Returns true if resources are indeed evicted as a
94  // result of this call.
95  bool ReduceMemoryOnImplThread(size_t limit_bytes,
96                                int priority_cutoff,
97                                ResourceProvider* resource_provider);
98
99  // Returns true if there exist any textures that are linked to backings that
100  // have had their resources evicted. Only when we commit a tree that has no
101  // textures linked to evicted backings may we allow drawing. After an
102  // eviction, this will not become true until unlinkAndClearEvictedBackings
103  // is called.
104  bool LinkedEvictedBackingsExist() const;
105
106  // Unlink the list of contents textures' backings from their owning textures
107  // and delete the evicted backings' structures. This is called just before
108  // updating layers, and is only ever called on the main thread.
109  void UnlinkAndClearEvictedBackings();
110
111  bool RequestLate(PrioritizedResource* texture);
112
113  void ReduceWastedMemory(ResourceProvider* resource_provider);
114  void ReduceMemory(ResourceProvider* resource_provider);
115  void ClearAllMemory(ResourceProvider* resource_provider);
116
117  void AcquireBackingTextureIfNeeded(PrioritizedResource* texture,
118                                     ResourceProvider* resource_provider);
119
120  void RegisterTexture(PrioritizedResource* texture);
121  void UnregisterTexture(PrioritizedResource* texture);
122  void ReturnBackingTexture(PrioritizedResource* texture);
123
124  // Update all backings' priorities from their owning texture.
125  void PushTexturePrioritiesToBackings();
126
127  // Mark all textures' backings as being in the drawing impl tree.
128  void UpdateBackingsState(ResourceProvider* resource_provider);
129
130  const Proxy* ProxyForDebug() const;
131
132 private:
133  friend class PrioritizedResourceTest;
134
135  enum EvictionPolicy {
136    EVICT_ONLY_RECYCLABLE,
137    EVICT_ANYTHING,
138  };
139  enum UnlinkPolicy {
140    DO_NOT_UNLINK_BACKINGS,
141    UNLINK_BACKINGS,
142  };
143
144  // Compare textures. Highest priority first.
145  static inline bool CompareTextures(PrioritizedResource* a,
146                                     PrioritizedResource* b) {
147    if (a->request_priority() == b->request_priority())
148      return a < b;
149    return PriorityCalculator::priority_is_higher(a->request_priority(),
150                                                  b->request_priority());
151  }
152  // Compare backings. Lowest priority first.
153  static inline bool CompareBackings(PrioritizedResource::Backing* a,
154                                     PrioritizedResource::Backing* b) {
155    // Make textures that can be recycled appear first.
156    if (a->CanBeRecycledIfNotInExternalUse() !=
157        b->CanBeRecycledIfNotInExternalUse())
158      return (a->CanBeRecycledIfNotInExternalUse() >
159              b->CanBeRecycledIfNotInExternalUse());
160    // Then sort by being above or below the priority cutoff.
161    if (a->was_above_priority_cutoff_at_last_priority_update() !=
162        b->was_above_priority_cutoff_at_last_priority_update())
163      return (a->was_above_priority_cutoff_at_last_priority_update() <
164              b->was_above_priority_cutoff_at_last_priority_update());
165    // Then sort by priority (note that backings that no longer have owners will
166    // always have the lowest priority).
167    if (a->request_priority_at_last_priority_update() !=
168        b->request_priority_at_last_priority_update())
169      return PriorityCalculator::priority_is_lower(
170          a->request_priority_at_last_priority_update(),
171          b->request_priority_at_last_priority_update());
172    // Then sort by being in the impl tree versus being completely
173    // unreferenced.
174    if (a->in_drawing_impl_tree() != b->in_drawing_impl_tree())
175      return (a->in_drawing_impl_tree() < b->in_drawing_impl_tree());
176    // Finally, prefer to evict textures in the parent compositor because
177    // they will otherwise take another roundtrip to the parent compositor
178    // before they are evicted.
179    if (a->in_parent_compositor() != b->in_parent_compositor())
180      return (a->in_parent_compositor() > b->in_parent_compositor());
181    return a < b;
182  }
183
184  explicit PrioritizedResourceManager(const Proxy* proxy);
185
186  bool EvictBackingsToReduceMemory(size_t limit_bytes,
187                                   int priority_cutoff,
188                                   EvictionPolicy eviction_policy,
189                                   UnlinkPolicy unlink_policy,
190                                   ResourceProvider* resource_provider);
191  PrioritizedResource::Backing* CreateBacking(
192      const gfx::Size& size,
193      ResourceFormat format,
194      ResourceProvider* resource_provider);
195  void EvictFirstBackingResource(ResourceProvider* resource_provider);
196  void SortBackings();
197
198  void AssertInvariants();
199
200  size_t max_memory_limit_bytes_;
201  // The priority cutoff based on memory pressure. This is not a strict
202  // cutoff -- RequestLate allows textures with priority equal to this
203  // cutoff to be allowed.
204  int priority_cutoff_;
205  // The priority cutoff based on external memory policy. This is a strict
206  // cutoff -- no textures with priority equal to this cutoff will be allowed.
207  int external_priority_cutoff_;
208  size_t memory_use_bytes_;
209  size_t memory_above_cutoff_bytes_;
210  size_t max_memory_needed_bytes_;
211  size_t memory_available_bytes_;
212
213  typedef base::hash_set<PrioritizedResource*> TextureSet;
214  typedef std::vector<PrioritizedResource*> TextureVector;
215
216  const Proxy* proxy_;
217
218  TextureSet textures_;
219  // This list is always sorted in eviction order, with the exception the
220  // newly-allocated or recycled textures at the very end of the tail that
221  // are not sorted by priority.
222  BackingList backings_;
223  bool backings_tail_not_sorted_;
224
225  // The list of backings that have been evicted, but may still be linked
226  // to textures. This can be accessed concurrently by the main and impl
227  // threads, and may only be accessed while holding evicted_backings_lock_.
228  mutable base::Lock evicted_backings_lock_;
229  BackingList evicted_backings_;
230
231  TextureVector temp_texture_vector_;
232
233  // Statistics about memory usage at priority cutoffs, computed at
234  // PrioritizeTextures.
235  size_t memory_visible_bytes_;
236  size_t memory_visible_and_nearby_bytes_;
237
238  // Statistics copied at the time of PushTexturePrioritiesToBackings.
239  size_t memory_visible_last_pushed_bytes_;
240  size_t memory_visible_and_nearby_last_pushed_bytes_;
241
242  DISALLOW_COPY_AND_ASSIGN(PrioritizedResourceManager);
243};
244
245}  // namespace cc
246
247#endif  // CC_RESOURCES_PRIORITIZED_RESOURCE_MANAGER_H_
248