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 "third_party/khronos/GLES2/gl2.h" 21 #include "ui/gfx/size.h" 22 23 #if defined(COMPILER_GCC) 24 namespace BASE_HASH_NAMESPACE { 25 template <> struct hash<cc::PrioritizedResource*> { 26 size_t operator()(cc::PrioritizedResource* ptr) const { 27 return hash<size_t>()(reinterpret_cast<size_t>(ptr)); 28 } 29 }; 30 } // namespace BASE_HASH_NAMESPACE 31 #endif // COMPILER 32 33 namespace cc { 34 35 class PriorityCalculator; 36 class Proxy; 37 38 class CC_EXPORT PrioritizedResourceManager { 39 public: 40 static scoped_ptr<PrioritizedResourceManager> Create(const Proxy* proxy) { 41 return make_scoped_ptr(new PrioritizedResourceManager(proxy)); 42 } 43 scoped_ptr<PrioritizedResource> CreateTexture(gfx::Size size, GLenum 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 81 // Return the amount of texture memory required at particular cutoffs. 82 size_t MemoryVisibleBytes() const; 83 size_t MemoryVisibleAndNearbyBytes() const; 84 85 void PrioritizeTextures(); 86 void ClearPriorities(); 87 88 // Delete contents textures' backing resources until they use only 89 // limit_bytes bytes. This may be called on the impl thread while the main 90 // thread is running. Returns true if resources are indeed evicted as a 91 // result of this call. 92 bool ReduceMemoryOnImplThread(size_t limit_bytes, 93 int priority_cutoff, 94 ResourceProvider* resource_provider); 95 96 // Delete contents textures' backing resources that can be recycled. This 97 // may be called on the impl thread while the main thread is running. 98 void ReduceWastedMemoryOnImplThread(ResourceProvider* resource_provider); 99 100 // Returns true if there exist any textures that are linked to backings that 101 // have had their resources evicted. Only when we commit a tree that has no 102 // textures linked to evicted backings may we allow drawing. After an 103 // eviction, this will not become true until unlinkAndClearEvictedBackings 104 // is called. 105 bool LinkedEvictedBackingsExist() const; 106 107 // Unlink the list of contents textures' backings from their owning textures 108 // and delete the evicted backings' structures. This is called just before 109 // updating layers, and is only ever called on the main thread. 110 void UnlinkAndClearEvictedBackings(); 111 112 bool RequestLate(PrioritizedResource* texture); 113 114 void ReduceWastedMemory(ResourceProvider* resource_provider); 115 void ReduceMemory(ResourceProvider* resource_provider); 116 void ClearAllMemory(ResourceProvider* resource_provider); 117 118 void AcquireBackingTextureIfNeeded(PrioritizedResource* texture, 119 ResourceProvider* resource_provider); 120 121 void RegisterTexture(PrioritizedResource* texture); 122 void UnregisterTexture(PrioritizedResource* texture); 123 void ReturnBackingTexture(PrioritizedResource* texture); 124 125 // Update all backings' priorities from their owning texture. 126 void PushTexturePrioritiesToBackings(); 127 128 // Mark all textures' backings as being in the drawing impl tree. 129 void UpdateBackingsInDrawingImplTree(); 130 131 const Proxy* ProxyForDebug() const; 132 133 private: 134 friend class PrioritizedResourceTest; 135 136 enum EvictionPolicy { 137 EVICT_ONLY_RECYCLABLE, 138 EVICT_ANYTHING, 139 }; 140 enum UnlinkPolicy { 141 DO_NOT_UNLINK_BACKINGS, 142 UNLINK_BACKINGS, 143 }; 144 145 // Compare textures. Highest priority first. 146 static inline bool CompareTextures(PrioritizedResource* a, 147 PrioritizedResource* b) { 148 if (a->request_priority() == b->request_priority()) 149 return a < b; 150 return PriorityCalculator::priority_is_higher(a->request_priority(), 151 b->request_priority()); 152 } 153 // Compare backings. Lowest priority first. 154 static inline bool CompareBackings(PrioritizedResource::Backing* a, 155 PrioritizedResource::Backing* b) { 156 // Make textures that can be recycled appear first 157 if (a->CanBeRecycled() != b->CanBeRecycled()) 158 return (a->CanBeRecycled() > b->CanBeRecycled()); 159 // Then sort by being above or below the priority cutoff. 160 if (a->was_above_priority_cutoff_at_last_priority_update() != 161 b->was_above_priority_cutoff_at_last_priority_update()) 162 return (a->was_above_priority_cutoff_at_last_priority_update() < 163 b->was_above_priority_cutoff_at_last_priority_update()); 164 // Then sort by priority (note that backings that no longer have owners will 165 // always have the lowest priority) 166 if (a->request_priority_at_last_priority_update() != 167 b->request_priority_at_last_priority_update()) 168 return PriorityCalculator::priority_is_lower( 169 a->request_priority_at_last_priority_update(), 170 b->request_priority_at_last_priority_update()); 171 // Finally sort by being in the impl tree versus being completely 172 // unreferenced 173 if (a->in_drawing_impl_tree() != b->in_drawing_impl_tree()) 174 return (a->in_drawing_impl_tree() < b->in_drawing_impl_tree()); 175 return a < b; 176 } 177 178 explicit PrioritizedResourceManager(const Proxy* proxy); 179 180 bool EvictBackingsToReduceMemory(size_t limit_bytes, 181 int priority_cutoff, 182 EvictionPolicy eviction_policy, 183 UnlinkPolicy unlink_policy, 184 ResourceProvider* resource_provider); 185 PrioritizedResource::Backing* CreateBacking( 186 gfx::Size size, 187 GLenum format, 188 ResourceProvider* resource_provider); 189 void EvictFirstBackingResource(ResourceProvider* resource_provider); 190 void SortBackings(); 191 192 void AssertInvariants(); 193 194 size_t max_memory_limit_bytes_; 195 // The priority cutoff based on memory pressure. This is not a strict 196 // cutoff -- RequestLate allows textures with priority equal to this 197 // cutoff to be allowed. 198 int priority_cutoff_; 199 // The priority cutoff based on external memory policy. This is a strict 200 // cutoff -- no textures with priority equal to this cutoff will be allowed. 201 int external_priority_cutoff_; 202 size_t memory_use_bytes_; 203 size_t memory_above_cutoff_bytes_; 204 size_t max_memory_needed_bytes_; 205 size_t memory_available_bytes_; 206 207 typedef base::hash_set<PrioritizedResource*> TextureSet; 208 typedef std::vector<PrioritizedResource*> TextureVector; 209 210 const Proxy* proxy_; 211 212 TextureSet textures_; 213 // This list is always sorted in eviction order, with the exception the 214 // newly-allocated or recycled textures at the very end of the tail that 215 // are not sorted by priority. 216 BackingList backings_; 217 bool backings_tail_not_sorted_; 218 219 // The list of backings that have been evicted, but may still be linked 220 // to textures. This can be accessed concurrently by the main and impl 221 // threads, and may only be accessed while holding evicted_backings_lock_. 222 mutable base::Lock evicted_backings_lock_; 223 BackingList evicted_backings_; 224 225 TextureVector temp_texture_vector_; 226 227 // Statistics about memory usage at priority cutoffs, computed at 228 // PrioritizeTextures. 229 size_t memory_visible_bytes_; 230 size_t memory_visible_and_nearby_bytes_; 231 232 // Statistics copied at the time of PushTexturePrioritiesToBackings. 233 size_t memory_visible_last_pushed_bytes_; 234 size_t memory_visible_and_nearby_last_pushed_bytes_; 235 236 DISALLOW_COPY_AND_ASSIGN(PrioritizedResourceManager); 237 }; 238 239 } // namespace cc 240 241 #endif // CC_RESOURCES_PRIORITIZED_RESOURCE_MANAGER_H_ 242