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