1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef GrResourceCache_DEFINED 9 #define GrResourceCache_DEFINED 10 11 #include "GrGpuResource.h" 12 #include "GrGpuResourceCacheAccess.h" 13 #include "GrGpuResourcePriv.h" 14 #include "GrResourceKey.h" 15 #include "SkMessageBus.h" 16 #include "SkRefCnt.h" 17 #include "SkTArray.h" 18 #include "SkTDPQueue.h" 19 #include "SkTInternalLList.h" 20 #include "SkTMultiMap.h" 21 22 class GrCaps; 23 class GrProxyProvider; 24 class SkString; 25 class SkTraceMemoryDump; 26 class GrSingleOwner; 27 28 struct GrGpuResourceFreedMessage { 29 GrGpuResource* fResource; 30 uint32_t fOwningUniqueID; 31 }; 32 33 static inline bool SkShouldPostMessageToBus( 34 const GrGpuResourceFreedMessage& msg, uint32_t msgBusUniqueID) { 35 // The inbox's ID is the unique ID of the owning GrContext. 36 return msgBusUniqueID == msg.fOwningUniqueID; 37 } 38 39 /** 40 * Manages the lifetime of all GrGpuResource instances. 41 * 42 * Resources may have optionally have two types of keys: 43 * 1) A scratch key. This is for resources whose allocations are cached but not their contents. 44 * Multiple resources can share the same scratch key. This is so a caller can have two 45 * resource instances with the same properties (e.g. multipass rendering that ping-pongs 46 * between two temporary surfaces). The scratch key is set at resource creation time and 47 * should never change. Resources need not have a scratch key. 48 * 2) A unique key. This key's meaning is specific to the domain that created the key. Only one 49 * resource may have a given unique key. The unique key can be set, cleared, or changed 50 * anytime after resource creation. 51 * 52 * A unique key always takes precedence over a scratch key when a resource has both types of keys. 53 * If a resource has neither key type then it will be deleted as soon as the last reference to it 54 * is dropped. 55 */ 56 class GrResourceCache { 57 public: 58 GrResourceCache(const GrCaps*, GrSingleOwner* owner, uint32_t contextUniqueID); 59 ~GrResourceCache(); 60 61 // Default maximum number of budgeted resources in the cache. 62 static const int kDefaultMaxCount = 2 * (1 << 12); 63 // Default maximum number of bytes of gpu memory of budgeted resources in the cache. 64 static const size_t kDefaultMaxSize = 96 * (1 << 20); 65 66 /** Used to access functionality needed by GrGpuResource for lifetime management. */ 67 class ResourceAccess; 68 ResourceAccess resourceAccess(); 69 70 /** Unique ID of the owning GrContext. */ 71 uint32_t contextUniqueID() const { return fContextUniqueID; } 72 73 /** Sets the cache limits in terms of number of resources and max gpu memory byte size. */ 74 void setLimits(int count, size_t bytes); 75 76 /** 77 * Returns the number of resources. 78 */ 79 int getResourceCount() const { 80 return fPurgeableQueue.count() + fNonpurgeableResources.count(); 81 } 82 83 /** 84 * Returns the number of resources that count against the budget. 85 */ 86 int getBudgetedResourceCount() const { return fBudgetedCount; } 87 88 /** 89 * Returns the number of bytes consumed by resources. 90 */ 91 size_t getResourceBytes() const { return fBytes; } 92 93 /** 94 * Returns the number of bytes held by unlocked reosources which are available for purging. 95 */ 96 size_t getPurgeableBytes() const { return fPurgeableBytes; } 97 98 /** 99 * Returns the number of bytes consumed by budgeted resources. 100 */ 101 size_t getBudgetedResourceBytes() const { return fBudgetedBytes; } 102 103 /** 104 * Returns the cached resources count budget. 105 */ 106 int getMaxResourceCount() const { return fMaxCount; } 107 108 /** 109 * Returns the number of bytes consumed by cached resources. 110 */ 111 size_t getMaxResourceBytes() const { return fMaxBytes; } 112 113 /** 114 * Abandons the backend API resources owned by all GrGpuResource objects and removes them from 115 * the cache. 116 */ 117 void abandonAll(); 118 119 /** 120 * Releases the backend API resources owned by all GrGpuResource objects and removes them from 121 * the cache. 122 */ 123 void releaseAll(); 124 125 enum class ScratchFlags { 126 kNone = 0, 127 /** Preferentially returns scratch resources with no pending IO. */ 128 kPreferNoPendingIO = 0x1, 129 /** Will not return any resources that match but have pending IO. */ 130 kRequireNoPendingIO = 0x2, 131 }; 132 133 /** 134 * Find a resource that matches a scratch key. 135 */ 136 GrGpuResource* findAndRefScratchResource(const GrScratchKey& scratchKey, size_t resourceSize, 137 ScratchFlags); 138 139 #ifdef SK_DEBUG 140 // This is not particularly fast and only used for validation, so debug only. 141 int countScratchEntriesForKey(const GrScratchKey& scratchKey) const { 142 return fScratchMap.countForKey(scratchKey); 143 } 144 #endif 145 146 /** 147 * Find a resource that matches a unique key. 148 */ 149 GrGpuResource* findAndRefUniqueResource(const GrUniqueKey& key) { 150 GrGpuResource* resource = fUniqueHash.find(key); 151 if (resource) { 152 this->refAndMakeResourceMRU(resource); 153 } 154 return resource; 155 } 156 157 /** 158 * Query whether a unique key exists in the cache. 159 */ 160 bool hasUniqueKey(const GrUniqueKey& key) const { 161 return SkToBool(fUniqueHash.find(key)); 162 } 163 164 /** Purges resources to become under budget and processes resources with invalidated unique 165 keys. */ 166 void purgeAsNeeded(); 167 168 /** Purges all resources that don't have external owners. */ 169 void purgeAllUnlocked() { this->purgeUnlockedResources(false); } 170 171 // Purge unlocked resources. If 'scratchResourcesOnly' is true the purgeable resources 172 // containing persistent data are spared. If it is false then all purgeable resources will 173 // be deleted. 174 void purgeUnlockedResources(bool scratchResourcesOnly); 175 176 /** Purge all resources not used since the passed in time. */ 177 void purgeResourcesNotUsedSince(GrStdSteadyClock::time_point); 178 179 bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCount > fMaxCount; } 180 181 /** 182 * Purge unlocked resources from the cache until the the provided byte count has been reached 183 * or we have purged all unlocked resources. The default policy is to purge in LRU order, but 184 * can be overridden to prefer purging scratch resources (in LRU order) prior to purging other 185 * resource types. 186 * 187 * @param maxBytesToPurge the desired number of bytes to be purged. 188 * @param preferScratchResources If true scratch resources will be purged prior to other 189 * resource types. 190 */ 191 void purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources); 192 193 /** Returns true if the cache would like a flush to occur in order to make more resources 194 purgeable. */ 195 bool requestsFlush() const { return this->overBudget() && !fPurgeableQueue.count(); } 196 197 /** Maintain a ref to this resource until we receive a GrGpuResourceFreedMessage. */ 198 void insertCrossContextGpuResource(GrGpuResource* resource); 199 200 #if GR_CACHE_STATS 201 struct Stats { 202 int fTotal; 203 int fNumPurgeable; 204 int fNumNonPurgeable; 205 206 int fScratch; 207 int fWrapped; 208 size_t fUnbudgetedSize; 209 210 Stats() { this->reset(); } 211 212 void reset() { 213 fTotal = 0; 214 fNumPurgeable = 0; 215 fNumNonPurgeable = 0; 216 fScratch = 0; 217 fWrapped = 0; 218 fUnbudgetedSize = 0; 219 } 220 221 void update(GrGpuResource* resource) { 222 if (resource->cacheAccess().isScratch()) { 223 ++fScratch; 224 } 225 if (resource->resourcePriv().refsWrappedObjects()) { 226 ++fWrapped; 227 } 228 if (GrBudgetedType::kBudgeted != resource->resourcePriv().budgetedType()) { 229 fUnbudgetedSize += resource->gpuMemorySize(); 230 } 231 } 232 }; 233 234 void getStats(Stats*) const; 235 236 void dumpStats(SkString*) const; 237 238 void dumpStatsKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* value) const; 239 #endif 240 241 #ifdef SK_DEBUG 242 int countUniqueKeysWithTag(const char* tag) const; 243 #endif 244 245 // This function is for unit testing and is only defined in test tools. 246 void changeTimestamp(uint32_t newTimestamp); 247 248 // Enumerates all cached resources and dumps their details to traceMemoryDump. 249 void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; 250 251 void setProxyProvider(GrProxyProvider* proxyProvider) { fProxyProvider = proxyProvider; } 252 253 private: 254 /////////////////////////////////////////////////////////////////////////// 255 /// @name Methods accessible via ResourceAccess 256 //// 257 void insertResource(GrGpuResource*); 258 void removeResource(GrGpuResource*); 259 void notifyCntReachedZero(GrGpuResource*, uint32_t flags); 260 void changeUniqueKey(GrGpuResource*, const GrUniqueKey&); 261 void removeUniqueKey(GrGpuResource*); 262 void willRemoveScratchKey(const GrGpuResource*); 263 void didChangeBudgetStatus(GrGpuResource*); 264 void refAndMakeResourceMRU(GrGpuResource*); 265 /// @} 266 267 void processFreedGpuResources(); 268 void addToNonpurgeableArray(GrGpuResource*); 269 void removeFromNonpurgeableArray(GrGpuResource*); 270 271 bool wouldFit(size_t bytes) { 272 return fBudgetedBytes+bytes <= fMaxBytes && fBudgetedCount+1 <= fMaxCount; 273 } 274 275 uint32_t getNextTimestamp(); 276 277 #ifdef SK_DEBUG 278 bool isInCache(const GrGpuResource* r) const; 279 void validate() const; 280 #else 281 void validate() const {} 282 #endif 283 284 class AutoValidate; 285 286 class AvailableForScratchUse; 287 288 struct ScratchMapTraits { 289 static const GrScratchKey& GetKey(const GrGpuResource& r) { 290 return r.resourcePriv().getScratchKey(); 291 } 292 293 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); } 294 static void OnFree(GrGpuResource*) { } 295 }; 296 typedef SkTMultiMap<GrGpuResource, GrScratchKey, ScratchMapTraits> ScratchMap; 297 298 struct UniqueHashTraits { 299 static const GrUniqueKey& GetKey(const GrGpuResource& r) { return r.getUniqueKey(); } 300 301 static uint32_t Hash(const GrUniqueKey& key) { return key.hash(); } 302 }; 303 typedef SkTDynamicHash<GrGpuResource, GrUniqueKey, UniqueHashTraits> UniqueHash; 304 305 static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const& b) { 306 return a->cacheAccess().timestamp() < b->cacheAccess().timestamp(); 307 } 308 309 static int* AccessResourceIndex(GrGpuResource* const& res) { 310 return res->cacheAccess().accessCacheIndex(); 311 } 312 313 typedef SkMessageBus<GrUniqueKeyInvalidatedMessage>::Inbox InvalidUniqueKeyInbox; 314 typedef SkMessageBus<GrGpuResourceFreedMessage>::Inbox FreedGpuResourceInbox; 315 typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> PurgeableQueue; 316 typedef SkTDArray<GrGpuResource*> ResourceArray; 317 318 GrProxyProvider* fProxyProvider; 319 // Whenever a resource is added to the cache or the result of a cache lookup, fTimestamp is 320 // assigned as the resource's timestamp and then incremented. fPurgeableQueue orders the 321 // purgeable resources by this value, and thus is used to purge resources in LRU order. 322 uint32_t fTimestamp; 323 PurgeableQueue fPurgeableQueue; 324 ResourceArray fNonpurgeableResources; 325 326 // This map holds all resources that can be used as scratch resources. 327 ScratchMap fScratchMap; 328 // This holds all resources that have unique keys. 329 UniqueHash fUniqueHash; 330 331 // our budget, used in purgeAsNeeded() 332 int fMaxCount; 333 size_t fMaxBytes; 334 335 #if GR_CACHE_STATS 336 int fHighWaterCount; 337 size_t fHighWaterBytes; 338 int fBudgetedHighWaterCount; 339 size_t fBudgetedHighWaterBytes; 340 #endif 341 342 // our current stats for all resources 343 SkDEBUGCODE(int fCount;) 344 size_t fBytes; 345 346 // our current stats for resources that count against the budget 347 int fBudgetedCount; 348 size_t fBudgetedBytes; 349 size_t fPurgeableBytes; 350 351 InvalidUniqueKeyInbox fInvalidUniqueKeyInbox; 352 FreedGpuResourceInbox fFreedGpuResourceInbox; 353 354 SkTDArray<GrGpuResource*> fResourcesWaitingForFreeMsg; 355 356 uint32_t fContextUniqueID; 357 GrSingleOwner* fSingleOwner; 358 359 // This resource is allowed to be in the nonpurgeable array for the sake of validate() because 360 // we're in the midst of converting it to purgeable status. 361 SkDEBUGCODE(GrGpuResource* fNewlyPurgeableResourceForValidation;) 362 363 bool fPreferVRAMUseOverFlushes; 364 }; 365 366 GR_MAKE_BITFIELD_CLASS_OPS(GrResourceCache::ScratchFlags); 367 368 class GrResourceCache::ResourceAccess { 369 private: 370 ResourceAccess(GrResourceCache* cache) : fCache(cache) { } 371 ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { } 372 ResourceAccess& operator=(const ResourceAccess&); // unimpl 373 374 /** 375 * Insert a resource into the cache. 376 */ 377 void insertResource(GrGpuResource* resource) { fCache->insertResource(resource); } 378 379 /** 380 * Removes a resource from the cache. 381 */ 382 void removeResource(GrGpuResource* resource) { fCache->removeResource(resource); } 383 384 /** 385 * Notifications that should be sent to the cache when the ref/io cnt status of resources 386 * changes. 387 */ 388 enum RefNotificationFlags { 389 /** All types of refs on the resource have reached zero. */ 390 kAllCntsReachedZero_RefNotificationFlag = 0x1, 391 /** The normal (not pending IO type) ref cnt has reached zero. */ 392 kRefCntReachedZero_RefNotificationFlag = 0x2, 393 }; 394 /** 395 * Called by GrGpuResources when they detect that their ref/io cnts have reached zero. When the 396 * normal ref cnt reaches zero the flags that are set should be: 397 * a) kRefCntReachedZero if a pending IO cnt is still non-zero. 398 * b) (kRefCntReachedZero | kAllCntsReachedZero) when all pending IO cnts are also zero. 399 * kAllCntsReachedZero is set by itself if a pending IO cnt is decremented to zero and all the 400 * the other cnts are already zero. 401 */ 402 void notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) { 403 fCache->notifyCntReachedZero(resource, flags); 404 } 405 406 /** 407 * Called by GrGpuResources to change their unique keys. 408 */ 409 void changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) { 410 fCache->changeUniqueKey(resource, newKey); 411 } 412 413 /** 414 * Called by a GrGpuResource to remove its unique key. 415 */ 416 void removeUniqueKey(GrGpuResource* resource) { fCache->removeUniqueKey(resource); } 417 418 /** 419 * Called by a GrGpuResource when it removes its scratch key. 420 */ 421 void willRemoveScratchKey(const GrGpuResource* resource) { 422 fCache->willRemoveScratchKey(resource); 423 } 424 425 /** 426 * Called by GrGpuResources when they change from budgeted to unbudgeted or vice versa. 427 */ 428 void didChangeBudgetStatus(GrGpuResource* resource) { fCache->didChangeBudgetStatus(resource); } 429 430 // No taking addresses of this type. 431 const ResourceAccess* operator&() const; 432 ResourceAccess* operator&(); 433 434 GrResourceCache* fCache; 435 436 friend class GrGpuResource; // To access all the proxy inline methods. 437 friend class GrResourceCache; // To create this type. 438 }; 439 440 inline GrResourceCache::ResourceAccess GrResourceCache::resourceAccess() { 441 return ResourceAccess(this); 442 } 443 444 #endif 445