blob: 8331bf5d1642b44e82b813d5ab2a800719076732 [file] [log] [blame]
bsalomonc8dc1f72014-08-21 13:02:13 -07001
2/*
3 * Copyright 2014 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
bsalomon0ea80f42015-02-11 10:49:59 -08009#ifndef GrResourceCache_DEFINED
10#define GrResourceCache_DEFINED
bsalomonc8dc1f72014-08-21 13:02:13 -070011
bsalomon744998e2014-08-28 09:54:34 -070012#include "GrGpuResource.h"
bsalomon9f2d1572015-02-17 11:47:40 -080013#include "GrGpuResourceCacheAccess.h"
bsalomon3582d3e2015-02-13 14:20:05 -080014#include "GrGpuResourcePriv.h"
bsalomon744998e2014-08-28 09:54:34 -070015#include "GrResourceKey.h"
bsalomon23e619c2015-02-06 11:54:28 -080016#include "SkMessageBus.h"
bsalomon8b79d232014-11-10 10:19:06 -080017#include "SkRefCnt.h"
bsalomon23e619c2015-02-06 11:54:28 -080018#include "SkTArray.h"
bsalomon9f2d1572015-02-17 11:47:40 -080019#include "SkTDPQueue.h"
bsalomonc8dc1f72014-08-21 13:02:13 -070020#include "SkTInternalLList.h"
bsalomon744998e2014-08-28 09:54:34 -070021#include "SkTMultiMap.h"
bsalomonc8dc1f72014-08-21 13:02:13 -070022
mtkleinb9eb4ac2015-02-02 18:26:03 -080023class SkString;
24
bsalomonc8dc1f72014-08-21 13:02:13 -070025/**
bsalomon71cb0c22014-11-14 12:10:14 -080026 * Manages the lifetime of all GrGpuResource instances.
27 *
28 * Resources may have optionally have two types of keys:
29 * 1) A scratch key. This is for resources whose allocations are cached but not their contents.
30 * Multiple resources can share the same scratch key. This is so a caller can have two
bsalomon84c8e622014-11-17 09:33:27 -080031 * resource instances with the same properties (e.g. multipass rendering that ping-pongs
bsalomon8718aaf2015-02-19 07:24:21 -080032 * between two temporary surfaces). The scratch key is set at resource creation time and
bsalomon71cb0c22014-11-14 12:10:14 -080033 * should never change. Resources need not have a scratch key.
bsalomon8718aaf2015-02-19 07:24:21 -080034 * 2) A unique key. This key's meaning is specific to the domain that created the key. Only one
bsalomonf99e9612015-02-19 08:24:16 -080035 * resource may have a given unique key. The unique key can be set, cleared, or changed
36 * anytime after resource creation.
37 *
bsalomon8718aaf2015-02-19 07:24:21 -080038 * A unique key always takes precedence over a scratch key when a resource has both types of keys.
bsalomon71cb0c22014-11-14 12:10:14 -080039 * If a resource has neither key type then it will be deleted as soon as the last reference to it
bsalomon8718aaf2015-02-19 07:24:21 -080040 * is dropped.
bsalomonc8dc1f72014-08-21 13:02:13 -070041 */
bsalomon0ea80f42015-02-11 10:49:59 -080042class GrResourceCache {
bsalomonc8dc1f72014-08-21 13:02:13 -070043public:
bsalomon0ea80f42015-02-11 10:49:59 -080044 GrResourceCache();
45 ~GrResourceCache();
bsalomonc8dc1f72014-08-21 13:02:13 -070046
bsalomon71cb0c22014-11-14 12:10:14 -080047 /** Used to access functionality needed by GrGpuResource for lifetime management. */
48 class ResourceAccess;
49 ResourceAccess resourceAccess();
bsalomonc8dc1f72014-08-21 13:02:13 -070050
bsalomon71cb0c22014-11-14 12:10:14 -080051 /**
52 * Sets the cache limits in terms of number of resources and max gpu memory byte size.
53 */
54 void setLimits(int count, size_t bytes);
bsalomonc8dc1f72014-08-21 13:02:13 -070055
bsalomon71cb0c22014-11-14 12:10:14 -080056 /**
bsalomondace19e2014-11-17 07:34:06 -080057 * Returns the number of resources.
bsalomon71cb0c22014-11-14 12:10:14 -080058 */
bsalomonf320e042015-02-17 15:09:34 -080059 int getResourceCount() const {
60 return fPurgeableQueue.count() + fNonpurgeableResources.count();
61 }
bsalomon8b79d232014-11-10 10:19:06 -080062
bsalomon71cb0c22014-11-14 12:10:14 -080063 /**
bsalomondace19e2014-11-17 07:34:06 -080064 * Returns the number of resources that count against the budget.
65 */
66 int getBudgetedResourceCount() const { return fBudgetedCount; }
67
68 /**
69 * Returns the number of bytes consumed by resources.
bsalomon71cb0c22014-11-14 12:10:14 -080070 */
71 size_t getResourceBytes() const { return fBytes; }
72
73 /**
bsalomondace19e2014-11-17 07:34:06 -080074 * Returns the number of bytes consumed by budgeted resources.
75 */
76 size_t getBudgetedResourceBytes() const { return fBudgetedBytes; }
77
78 /**
bsalomon71cb0c22014-11-14 12:10:14 -080079 * Returns the cached resources count budget.
80 */
81 int getMaxResourceCount() const { return fMaxCount; }
82
83 /**
84 * Returns the number of bytes consumed by cached resources.
85 */
86 size_t getMaxResourceBytes() const { return fMaxBytes; }
87
88 /**
89 * Abandons the backend API resources owned by all GrGpuResource objects and removes them from
90 * the cache.
91 */
bsalomonc8dc1f72014-08-21 13:02:13 -070092 void abandonAll();
93
bsalomon71cb0c22014-11-14 12:10:14 -080094 /**
95 * Releases the backend API resources owned by all GrGpuResource objects and removes them from
96 * the cache.
97 */
bsalomonc8dc1f72014-08-21 13:02:13 -070098 void releaseAll();
99
bsalomon000f8292014-10-15 19:04:14 -0700100 enum {
101 /** Preferentially returns scratch resources with no pending IO. */
102 kPreferNoPendingIO_ScratchFlag = 0x1,
103 /** Will not return any resources that match but have pending IO. */
104 kRequireNoPendingIO_ScratchFlag = 0x2,
105 };
bsalomon71cb0c22014-11-14 12:10:14 -0800106
107 /**
108 * Find a resource that matches a scratch key.
109 */
bsalomon7775c852014-12-30 12:50:52 -0800110 GrGpuResource* findAndRefScratchResource(const GrScratchKey& scratchKey, uint32_t flags = 0);
bsalomon8b79d232014-11-10 10:19:06 -0800111
112#ifdef SK_DEBUG
113 // This is not particularly fast and only used for validation, so debug only.
bsalomon7775c852014-12-30 12:50:52 -0800114 int countScratchEntriesForKey(const GrScratchKey& scratchKey) const {
bsalomon8b79d232014-11-10 10:19:06 -0800115 return fScratchMap.countForKey(scratchKey);
116 }
117#endif
118
bsalomon71cb0c22014-11-14 12:10:14 -0800119 /**
bsalomon8718aaf2015-02-19 07:24:21 -0800120 * Find a resource that matches a unique key.
bsalomon71cb0c22014-11-14 12:10:14 -0800121 */
bsalomon8718aaf2015-02-19 07:24:21 -0800122 GrGpuResource* findAndRefUniqueResource(const GrUniqueKey& key) {
123 GrGpuResource* resource = fUniqueHash.find(key);
bsalomon71cb0c22014-11-14 12:10:14 -0800124 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800125 this->refAndMakeResourceMRU(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800126 }
127 return resource;
bsalomon8b79d232014-11-10 10:19:06 -0800128 }
129
bsalomon71cb0c22014-11-14 12:10:14 -0800130 /**
bsalomon8718aaf2015-02-19 07:24:21 -0800131 * Query whether a unique key exists in the cache.
bsalomon71cb0c22014-11-14 12:10:14 -0800132 */
bsalomon8718aaf2015-02-19 07:24:21 -0800133 bool hasUniqueKey(const GrUniqueKey& key) const {
134 return SkToBool(fUniqueHash.find(key));
bsalomon8b79d232014-11-10 10:19:06 -0800135 }
bsalomonbcf0a522014-10-08 08:40:09 -0700136
bsalomon8718aaf2015-02-19 07:24:21 -0800137 /** Purges resources to become under budget and processes resources with invalidated unique
bsalomon23e619c2015-02-06 11:54:28 -0800138 keys. */
139 void purgeAsNeeded() {
bsalomon8718aaf2015-02-19 07:24:21 -0800140 SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs;
141 fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
bsalomon23e619c2015-02-06 11:54:28 -0800142 if (invalidKeyMsgs.count()) {
bsalomon8718aaf2015-02-19 07:24:21 -0800143 this->processInvalidUniqueKeys(invalidKeyMsgs);
bsalomon23e619c2015-02-06 11:54:28 -0800144 }
bsalomon9f2d1572015-02-17 11:47:40 -0800145 if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) {
bsalomon23e619c2015-02-06 11:54:28 -0800146 return;
147 }
148 this->internalPurgeAsNeeded();
149 }
150
bsalomon71cb0c22014-11-14 12:10:14 -0800151 /** Purges all resources that don't have external owners. */
152 void purgeAllUnlocked();
153
154 /**
155 * The callback function used by the cache when it is still over budget after a purge. The
156 * passed in 'data' is the same 'data' handed to setOverbudgetCallback.
157 */
158 typedef void (*PFOverBudgetCB)(void* data);
159
160 /**
161 * Set the callback the cache should use when it is still over budget after a purge. The 'data'
162 * provided here will be passed back to the callback. Note that the cache will attempt to purge
163 * any resources newly freed by the callback.
164 */
165 void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) {
166 fOverBudgetCB = overBudgetCB;
167 fOverBudgetData = data;
168 }
169
170#if GR_GPU_STATS
mtkleinb9eb4ac2015-02-02 18:26:03 -0800171 void dumpStats(SkString*) const;
bsalomon71cb0c22014-11-14 12:10:14 -0800172#endif
173
bsalomonddf30e62015-02-19 11:38:44 -0800174 // This function is for unit testing and is only defined in test tools.
175 void changeTimestamp(uint32_t newTimestamp);
176
bsalomonc8dc1f72014-08-21 13:02:13 -0700177private:
bsalomon71cb0c22014-11-14 12:10:14 -0800178 ///////////////////////////////////////////////////////////////////////////
179 /// @name Methods accessible via ResourceAccess
180 ////
181 void insertResource(GrGpuResource*);
182 void removeResource(GrGpuResource*);
bsalomon63c992f2015-01-23 12:47:59 -0800183 void notifyPurgeable(GrGpuResource*);
bsalomon71cb0c22014-11-14 12:10:14 -0800184 void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize);
bsalomonf99e9612015-02-19 08:24:16 -0800185 void changeUniqueKey(GrGpuResource*, const GrUniqueKey&);
186 void removeUniqueKey(GrGpuResource*);
bsalomon10e23ca2014-11-25 05:52:06 -0800187 void willRemoveScratchKey(const GrGpuResource*);
bsalomon84c8e622014-11-17 09:33:27 -0800188 void didChangeBudgetStatus(GrGpuResource*);
bsalomon9f2d1572015-02-17 11:47:40 -0800189 void refAndMakeResourceMRU(GrGpuResource*);
bsalomon71cb0c22014-11-14 12:10:14 -0800190 /// @}
191
bsalomon71cb0c22014-11-14 12:10:14 -0800192 void internalPurgeAsNeeded();
bsalomon8718aaf2015-02-19 07:24:21 -0800193 void processInvalidUniqueKeys(const SkTArray<GrUniqueKeyInvalidatedMessage>&);
bsalomonf320e042015-02-17 15:09:34 -0800194 void addToNonpurgeableArray(GrGpuResource*);
195 void removeFromNonpurgeableArray(GrGpuResource*);
196 bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCount > fMaxCount; }
bsalomon71cb0c22014-11-14 12:10:14 -0800197
bsalomonddf30e62015-02-19 11:38:44 -0800198 uint32_t getNextTimestamp();
199
bsalomon16961262014-08-26 14:01:07 -0700200#ifdef SK_DEBUG
bsalomonf320e042015-02-17 15:09:34 -0800201 bool isInCache(const GrGpuResource* r) const;
bsalomon71cb0c22014-11-14 12:10:14 -0800202 void validate() const;
203#else
204 void validate() const {}
bsalomon16961262014-08-26 14:01:07 -0700205#endif
206
bsalomon71cb0c22014-11-14 12:10:14 -0800207 class AutoValidate;
208
bsalomonbcf0a522014-10-08 08:40:09 -0700209 class AvailableForScratchUse;
bsalomon744998e2014-08-28 09:54:34 -0700210
bsalomon744998e2014-08-28 09:54:34 -0700211 struct ScratchMapTraits {
bsalomon7775c852014-12-30 12:50:52 -0800212 static const GrScratchKey& GetKey(const GrGpuResource& r) {
bsalomon3582d3e2015-02-13 14:20:05 -0800213 return r.resourcePriv().getScratchKey();
bsalomon744998e2014-08-28 09:54:34 -0700214 }
215
bsalomon7775c852014-12-30 12:50:52 -0800216 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
bsalomon744998e2014-08-28 09:54:34 -0700217 };
bsalomon7775c852014-12-30 12:50:52 -0800218 typedef SkTMultiMap<GrGpuResource, GrScratchKey, ScratchMapTraits> ScratchMap;
bsalomon744998e2014-08-28 09:54:34 -0700219
bsalomon8718aaf2015-02-19 07:24:21 -0800220 struct UniqueHashTraits {
221 static const GrUniqueKey& GetKey(const GrGpuResource& r) { return r.getUniqueKey(); }
bsalomon8b79d232014-11-10 10:19:06 -0800222
bsalomon8718aaf2015-02-19 07:24:21 -0800223 static uint32_t Hash(const GrUniqueKey& key) { return key.hash(); }
bsalomon8b79d232014-11-10 10:19:06 -0800224 };
bsalomon8718aaf2015-02-19 07:24:21 -0800225 typedef SkTDynamicHash<GrGpuResource, GrUniqueKey, UniqueHashTraits> UniqueHash;
bsalomon8b79d232014-11-10 10:19:06 -0800226
bsalomon9f2d1572015-02-17 11:47:40 -0800227 static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const& b) {
228 return a->cacheAccess().timestamp() < b->cacheAccess().timestamp();
229 }
bsalomon23e619c2015-02-06 11:54:28 -0800230
bsalomon9f2d1572015-02-17 11:47:40 -0800231 static int* AccessResourceIndex(GrGpuResource* const& res) {
232 return res->cacheAccess().accessCacheIndex();
233 }
234
bsalomon8718aaf2015-02-19 07:24:21 -0800235 typedef SkMessageBus<GrUniqueKeyInvalidatedMessage>::Inbox InvalidUniqueKeyInbox;
bsalomon9f2d1572015-02-17 11:47:40 -0800236 typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> PurgeableQueue;
bsalomonf320e042015-02-17 15:09:34 -0800237 typedef SkTDArray<GrGpuResource*> ResourceArray;
bsalomon9f2d1572015-02-17 11:47:40 -0800238
239 // Whenever a resource is added to the cache or the result of a cache lookup, fTimestamp is
240 // assigned as the resource's timestamp and then incremented. fPurgeableQueue orders the
241 // purgeable resources by this value, and thus is used to purge resources in LRU order.
242 uint32_t fTimestamp;
243 PurgeableQueue fPurgeableQueue;
bsalomonf320e042015-02-17 15:09:34 -0800244 ResourceArray fNonpurgeableResources;
bsalomon9f2d1572015-02-17 11:47:40 -0800245
bsalomon744998e2014-08-28 09:54:34 -0700246 // This map holds all resources that can be used as scratch resources.
bsalomon8b79d232014-11-10 10:19:06 -0800247 ScratchMap fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800248 // This holds all resources that have unique keys.
249 UniqueHash fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800250
251 // our budget, used in purgeAsNeeded()
252 int fMaxCount;
253 size_t fMaxBytes;
254
255#if GR_CACHE_STATS
256 int fHighWaterCount;
257 size_t fHighWaterBytes;
bsalomondace19e2014-11-17 07:34:06 -0800258 int fBudgetedHighWaterCount;
259 size_t fBudgetedHighWaterBytes;
bsalomon71cb0c22014-11-14 12:10:14 -0800260#endif
261
bsalomondace19e2014-11-17 07:34:06 -0800262 // our current stats for all resources
bsalomonf320e042015-02-17 15:09:34 -0800263 SkDEBUGCODE(int fCount;)
bsalomon71cb0c22014-11-14 12:10:14 -0800264 size_t fBytes;
265
bsalomondace19e2014-11-17 07:34:06 -0800266 // our current stats for resources that count against the budget
267 int fBudgetedCount;
268 size_t fBudgetedBytes;
269
bsalomon71cb0c22014-11-14 12:10:14 -0800270 PFOverBudgetCB fOverBudgetCB;
271 void* fOverBudgetData;
272
bsalomon8718aaf2015-02-19 07:24:21 -0800273 InvalidUniqueKeyInbox fInvalidUniqueKeyInbox;
bsalomonc8dc1f72014-08-21 13:02:13 -0700274};
275
bsalomon0ea80f42015-02-11 10:49:59 -0800276class GrResourceCache::ResourceAccess {
bsalomon71cb0c22014-11-14 12:10:14 -0800277private:
bsalomon0ea80f42015-02-11 10:49:59 -0800278 ResourceAccess(GrResourceCache* cache) : fCache(cache) { }
bsalomon71cb0c22014-11-14 12:10:14 -0800279 ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { }
280 ResourceAccess& operator=(const ResourceAccess&); // unimpl
281
282 /**
283 * Insert a resource into the cache.
284 */
285 void insertResource(GrGpuResource* resource) { fCache->insertResource(resource); }
286
287 /**
288 * Removes a resource from the cache.
289 */
290 void removeResource(GrGpuResource* resource) { fCache->removeResource(resource); }
291
292 /**
bsalomon63c992f2015-01-23 12:47:59 -0800293 * Called by GrGpuResources when they detects that they are newly purgeable.
bsalomon71cb0c22014-11-14 12:10:14 -0800294 */
bsalomon63c992f2015-01-23 12:47:59 -0800295 void notifyPurgeable(GrGpuResource* resource) { fCache->notifyPurgeable(resource); }
bsalomon71cb0c22014-11-14 12:10:14 -0800296
297 /**
298 * Called by GrGpuResources when their sizes change.
299 */
300 void didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
301 fCache->didChangeGpuMemorySize(resource, oldSize);
302 }
303
304 /**
bsalomonf99e9612015-02-19 08:24:16 -0800305 * Called by GrGpuResources to change their unique keys.
bsalomon71cb0c22014-11-14 12:10:14 -0800306 */
bsalomonf99e9612015-02-19 08:24:16 -0800307 void changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
308 fCache->changeUniqueKey(resource, newKey);
309 }
bsalomon71cb0c22014-11-14 12:10:14 -0800310
bsalomon10e23ca2014-11-25 05:52:06 -0800311 /**
bsalomonf99e9612015-02-19 08:24:16 -0800312 * Called by a GrGpuResource to remove its unique key.
bsalomon23e619c2015-02-06 11:54:28 -0800313 */
bsalomonf99e9612015-02-19 08:24:16 -0800314 void removeUniqueKey(GrGpuResource* resource) { fCache->removeUniqueKey(resource); }
bsalomon23e619c2015-02-06 11:54:28 -0800315
316 /**
317 * Called by a GrGpuResource when it removes its scratch key.
bsalomon10e23ca2014-11-25 05:52:06 -0800318 */
319 void willRemoveScratchKey(const GrGpuResource* resource) {
320 fCache->willRemoveScratchKey(resource);
321 }
bsalomon84c8e622014-11-17 09:33:27 -0800322
323 /**
324 * Called by GrGpuResources when they change from budgeted to unbudgeted or vice versa.
325 */
326 void didChangeBudgetStatus(GrGpuResource* resource) { fCache->didChangeBudgetStatus(resource); }
327
bsalomon71cb0c22014-11-14 12:10:14 -0800328 // No taking addresses of this type.
329 const ResourceAccess* operator&() const;
330 ResourceAccess* operator&();
331
bsalomon0ea80f42015-02-11 10:49:59 -0800332 GrResourceCache* fCache;
bsalomon71cb0c22014-11-14 12:10:14 -0800333
334 friend class GrGpuResource; // To access all the proxy inline methods.
bsalomon0ea80f42015-02-11 10:49:59 -0800335 friend class GrResourceCache; // To create this type.
bsalomon71cb0c22014-11-14 12:10:14 -0800336};
337
bsalomon0ea80f42015-02-11 10:49:59 -0800338inline GrResourceCache::ResourceAccess GrResourceCache::resourceAccess() {
bsalomon71cb0c22014-11-14 12:10:14 -0800339 return ResourceAccess(this);
340}
341
bsalomonc8dc1f72014-08-21 13:02:13 -0700342#endif