1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 11#ifndef GrResourceCache_DEFINED 12#define GrResourceCache_DEFINED 13 14#include "GrResourceKey.h" 15#include "SkTMultiMap.h" 16#include "SkMessageBus.h" 17#include "SkTInternalLList.h" 18 19class GrGpuResource; 20class GrResourceCache; 21class GrResourceCacheEntry; 22 23 24// The cache listens for these messages to purge junk resources proactively. 25struct GrResourceInvalidatedMessage { 26 GrResourceKey key; 27}; 28 29/////////////////////////////////////////////////////////////////////////////// 30 31class GrResourceCacheEntry { 32public: 33 GrGpuResource* resource() const { return fResource; } 34 const GrResourceKey& key() const { return fKey; } 35 36 static const GrResourceKey& GetKey(const GrResourceCacheEntry& e) { return e.key(); } 37 static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); } 38#ifdef SK_DEBUG 39 void validate() const; 40#else 41 void validate() const {} 42#endif 43 44 /** 45 * Update the cached size for this entry and inform the resource cache that 46 * it has changed. Usually invoked from GrGpuResource::didChangeGpuMemorySize, 47 * not directly from here. 48 */ 49 void didChangeResourceSize(); 50 51private: 52 GrResourceCacheEntry(GrResourceCache* resourceCache, 53 const GrResourceKey& key, 54 GrGpuResource* resource); 55 ~GrResourceCacheEntry(); 56 57 GrResourceCache* fResourceCache; 58 GrResourceKey fKey; 59 GrGpuResource* fResource; 60 size_t fCachedSize; 61 bool fIsExclusive; 62 63 // Linked list for the LRU ordering. 64 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry); 65 66 friend class GrResourceCache; 67 friend class GrContext; 68}; 69 70/////////////////////////////////////////////////////////////////////////////// 71 72/** 73 * Cache of GrGpuResource objects. 74 * 75 * These have a corresponding GrResourceKey, built from 128bits identifying the 76 * resource. Multiple resources can map to same GrResourceKey. 77 * 78 * The cache stores the entries in a double-linked list, which is its LRU. 79 * When an entry is "locked" (i.e. given to the caller), it is moved to the 80 * head of the list. If/when we must purge some of the entries, we walk the 81 * list backwards from the tail, since those are the least recently used. 82 * 83 * For fast searches, we maintain a hash map based on the GrResourceKey. 84 * 85 * It is a goal to make the GrResourceCache the central repository and bookkeeper 86 * of all resources. It should replace the linked list of GrGpuResources that 87 * GrGpu uses to call abandon/release. 88 */ 89class GrResourceCache { 90public: 91 GrResourceCache(int maxCount, size_t maxBytes); 92 ~GrResourceCache(); 93 94 /** 95 * Return the current resource cache limits. 96 * 97 * @param maxResource If non-null, returns maximum number of resources 98 * that can be held in the cache. 99 * @param maxBytes If non-null, returns maximum number of bytes of 100 * gpu memory that can be held in the cache. 101 */ 102 void getLimits(int* maxResources, size_t* maxBytes) const; 103 104 /** 105 * Specify the resource cache limits. If the current cache exceeds either 106 * of these, it will be purged (LRU) to keep the cache within these limits. 107 * 108 * @param maxResources The maximum number of resources that can be held in 109 * the cache. 110 * @param maxBytes The maximum number of bytes of resource memory that 111 * can be held in the cache. 112 */ 113 void setLimits(int maxResources, size_t maxResourceBytes); 114 115 /** 116 * The callback function used by the cache when it is still over budget 117 * after a purge. The passed in 'data' is the same 'data' handed to 118 * setOverbudgetCallback. The callback returns true if some resources 119 * have been freed. 120 */ 121 typedef bool (*PFOverbudgetCB)(void* data); 122 123 /** 124 * Set the callback the cache should use when it is still over budget 125 * after a purge. The 'data' provided here will be passed back to the 126 * callback. Note that the cache will attempt to purge any resources newly 127 * freed by the callback. 128 */ 129 void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) { 130 fOverbudgetCB = overbudgetCB; 131 fOverbudgetData = data; 132 } 133 134 /** 135 * Returns the number of bytes consumed by cached resources. 136 */ 137 size_t getCachedResourceBytes() const { return fEntryBytes; } 138 139 /** 140 * Returns the number of cached resources. 141 */ 142 int getCachedResourceCount() const { return fEntryCount; } 143 144 // For a found or added resource to be completely exclusive to the caller 145 // both the kNoOtherOwners and kHide flags need to be specified 146 enum OwnershipFlags { 147 kNoOtherOwners_OwnershipFlag = 0x1, // found/added resource has no other owners 148 kHide_OwnershipFlag = 0x2 // found/added resource is hidden from future 'find's 149 }; 150 151 /** 152 * Search for an entry with the same Key. If found, return it. 153 * If not found, return null. 154 * If ownershipFlags includes kNoOtherOwners and a resource is returned 155 * then that resource has no other refs to it. 156 * If ownershipFlags includes kHide and a resource is returned then that 157 * resource will not be returned from future 'find' calls until it is 158 * 'freed' (and recycled) or makeNonExclusive is called. 159 * For a resource to be completely exclusive to a caller both kNoOtherOwners 160 * and kHide must be specified. 161 */ 162 GrGpuResource* find(const GrResourceKey& key, 163 uint32_t ownershipFlags = 0); 164 165 /** 166 * Add the new resource to the cache (by creating a new cache entry based 167 * on the provided key and resource). 168 * 169 * Ownership of the resource is transferred to the resource cache, 170 * which will unref() it when it is purged or deleted. 171 * 172 * If ownershipFlags includes kHide, subsequent calls to 'find' will not 173 * return 'resource' until it is 'freed' (and recycled) or makeNonExclusive 174 * is called. 175 */ 176 void addResource(const GrResourceKey& key, 177 GrGpuResource* resource, 178 uint32_t ownershipFlags = 0); 179 180 /** 181 * Determines if the cache contains an entry matching a key. If a matching 182 * entry exists but was detached then it will not be found. 183 */ 184 bool hasKey(const GrResourceKey& key) const { return SkToBool(fCache.find(key)); } 185 186 /** 187 * Hide 'entry' so that future searches will not find it. Such 188 * hidden entries will not be purged. The entry still counts against 189 * the cache's budget and should be made non-exclusive when exclusive access 190 * is no longer needed. 191 */ 192 void makeExclusive(GrResourceCacheEntry* entry); 193 194 /** 195 * Restore 'entry' so that it can be found by future searches. 'entry' 196 * will also be purgeable (provided its lock count is now 0.) 197 */ 198 void makeNonExclusive(GrResourceCacheEntry* entry); 199 200 /** 201 * Notify the cache that the size of a resource has changed. 202 */ 203 void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc); 204 void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec); 205 206 /** 207 * Remove a resource from the cache and delete it! 208 */ 209 void deleteResource(GrResourceCacheEntry* entry); 210 211 /** 212 * Removes every resource in the cache that isn't locked. 213 */ 214 void purgeAllUnlocked(); 215 216 /** 217 * Allow cache to purge unused resources to obey resource limitations 218 * Note: this entry point will be hidden (again) once totally ref-driven 219 * cache maintenance is implemented. Note that the overbudget callback 220 * will be called if the initial purge doesn't get the cache under 221 * its budget. 222 * 223 * extraCount and extraBytes are added to the current resource allocation 224 * to make sure enough room is available for future additions (e.g, 225 * 10MB across 10 textures is about to be added). 226 */ 227 void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0); 228 229#ifdef SK_DEBUG 230 void validate() const; 231#else 232 void validate() const {} 233#endif 234 235#if GR_CACHE_STATS 236 void printStats(); 237#endif 238 239private: 240 enum BudgetBehaviors { 241 kAccountFor_BudgetBehavior, 242 kIgnore_BudgetBehavior 243 }; 244 245 void internalDetach(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior); 246 void attachToHead(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior); 247 248 void removeInvalidResource(GrResourceCacheEntry* entry); 249 250 SkTMultiMap<GrResourceCacheEntry, GrResourceKey> fCache; 251 252 // We're an internal doubly linked list 253 typedef SkTInternalLList<GrResourceCacheEntry> EntryList; 254 EntryList fList; 255 256#ifdef SK_DEBUG 257 // These objects cannot be returned by a search 258 EntryList fExclusiveList; 259#endif 260 261 // our budget, used in purgeAsNeeded() 262 int fMaxCount; 263 size_t fMaxBytes; 264 265 // our current stats, related to our budget 266#if GR_CACHE_STATS 267 int fHighWaterEntryCount; 268 size_t fHighWaterEntryBytes; 269 int fHighWaterClientDetachedCount; 270 size_t fHighWaterClientDetachedBytes; 271#endif 272 273 int fEntryCount; 274 size_t fEntryBytes; 275 int fClientDetachedCount; 276 size_t fClientDetachedBytes; 277 278 // prevents recursive purging 279 bool fPurging; 280 281 PFOverbudgetCB fOverbudgetCB; 282 void* fOverbudgetData; 283 284 void internalPurge(int extraCount, size_t extraBytes); 285 286 // Listen for messages that a resource has been invalidated and purge cached junk proactively. 287 SkMessageBus<GrResourceInvalidatedMessage>::Inbox fInvalidationInbox; 288 void purgeInvalidated(); 289 290#ifdef SK_DEBUG 291 static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list); 292#endif 293}; 294 295/////////////////////////////////////////////////////////////////////////////// 296 297#ifdef SK_DEBUG 298 class GrAutoResourceCacheValidate { 299 public: 300 GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) { 301 cache->validate(); 302 } 303 ~GrAutoResourceCacheValidate() { 304 fCache->validate(); 305 } 306 private: 307 GrResourceCache* fCache; 308 }; 309#else 310 class GrAutoResourceCacheValidate { 311 public: 312 GrAutoResourceCacheValidate(GrResourceCache*) {} 313 }; 314#endif 315 316#endif 317