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) 23 namespace BASE_HASH_NAMESPACE { 24 template <> 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 32 namespace cc { 33 34 class PriorityCalculator; 35 class Proxy; 36 37 class 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 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 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