3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
11 #ifndef GrResourceCache_DEFINED
12 #define GrResourceCache_DEFINED
14 #include "GrResourceKey.h"
15 #include "SkTMultiMap.h"
16 #include "SkMessageBus.h"
17 #include "SkTInternalLList.h"
20 class GrResourceCache;
21 class GrResourceCacheEntry;
24 // The cache listens for these messages to purge junk resources proactively.
25 struct GrResourceInvalidatedMessage {
29 ///////////////////////////////////////////////////////////////////////////////
31 class GrResourceCacheEntry {
33 GrGpuResource* resource() const { return fResource; }
34 const GrResourceKey& key() const { return fKey; }
36 static const GrResourceKey& GetKey(const GrResourceCacheEntry& e) { return e.key(); }
37 static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
39 void validate() const;
41 void validate() const {}
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.
49 void didChangeResourceSize();
52 GrResourceCacheEntry(GrResourceCache* resourceCache,
53 const GrResourceKey& key,
54 GrGpuResource* resource);
55 ~GrResourceCacheEntry();
57 GrResourceCache* fResourceCache;
59 GrGpuResource* fResource;
63 // Linked list for the LRU ordering.
64 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
66 friend class GrResourceCache;
67 friend class GrContext;
70 ///////////////////////////////////////////////////////////////////////////////
73 * Cache of GrGpuResource objects.
75 * These have a corresponding GrResourceKey, built from 128bits identifying the
76 * resource. Multiple resources can map to same GrResourceKey.
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.
83 * For fast searches, we maintain a hash map based on the GrResourceKey.
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.
89 class GrResourceCache {
91 GrResourceCache(int maxCount, size_t maxBytes);
95 * Return the current resource cache limits.
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.
102 void getLimits(int* maxResources, size_t* maxBytes) const;
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.
108 * @param maxResources The maximum number of resources that can be held in
110 * @param maxBytes The maximum number of bytes of resource memory that
111 * can be held in the cache.
113 void setLimits(int maxResources, size_t maxResourceBytes);
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
121 typedef bool (*PFOverbudgetCB)(void* data);
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.
129 void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
130 fOverbudgetCB = overbudgetCB;
131 fOverbudgetData = data;
135 * Returns the number of bytes consumed by cached resources.
137 size_t getCachedResourceBytes() const { return fEntryBytes; }
140 * Returns the number of cached resources.
142 int getCachedResourceCount() const { return fEntryCount; }
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
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.
162 GrGpuResource* find(const GrResourceKey& key,
163 uint32_t ownershipFlags = 0);
166 * Add the new resource to the cache (by creating a new cache entry based
167 * on the provided key and resource).
169 * Ownership of the resource is transferred to the resource cache,
170 * which will unref() it when it is purged or deleted.
172 * If ownershipFlags includes kHide, subsequent calls to 'find' will not
173 * return 'resource' until it is 'freed' (and recycled) or makeNonExclusive
176 void addResource(const GrResourceKey& key,
177 GrGpuResource* resource,
178 uint32_t ownershipFlags = 0);
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.
184 bool hasKey(const GrResourceKey& key) const { return SkToBool(fCache.find(key)); }
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.
192 void makeExclusive(GrResourceCacheEntry* entry);
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.)
198 void makeNonExclusive(GrResourceCacheEntry* entry);
201 * Notify the cache that the size of a resource has changed.
203 void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc);
204 void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec);
207 * Remove a resource from the cache and delete it!
209 void deleteResource(GrResourceCacheEntry* entry);
212 * Removes every resource in the cache that isn't locked.
214 void purgeAllUnlocked();
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
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).
227 void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
230 void validate() const;
232 void validate() const {}
240 enum BudgetBehaviors {
241 kAccountFor_BudgetBehavior,
242 kIgnore_BudgetBehavior
245 void internalDetach(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
246 void attachToHead(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
248 void removeInvalidResource(GrResourceCacheEntry* entry);
250 SkTMultiMap<GrResourceCacheEntry, GrResourceKey> fCache;
252 // We're an internal doubly linked list
253 typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
257 // These objects cannot be returned by a search
258 EntryList fExclusiveList;
261 // our budget, used in purgeAsNeeded()
265 // our current stats, related to our budget
267 int fHighWaterEntryCount;
268 size_t fHighWaterEntryBytes;
269 int fHighWaterClientDetachedCount;
270 size_t fHighWaterClientDetachedBytes;
275 int fClientDetachedCount;
276 size_t fClientDetachedBytes;
278 // prevents recursive purging
281 PFOverbudgetCB fOverbudgetCB;
282 void* fOverbudgetData;
284 void internalPurge(int extraCount, size_t extraBytes);
286 // Listen for messages that a resource has been invalidated and purge cached junk proactively.
287 SkMessageBus<GrResourceInvalidatedMessage>::Inbox fInvalidationInbox;
288 void purgeInvalidated();
291 static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
295 ///////////////////////////////////////////////////////////////////////////////
298 class GrAutoResourceCacheValidate {
300 GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
303 ~GrAutoResourceCacheValidate() {
307 GrResourceCache* fCache;
310 class GrAutoResourceCacheValidate {
312 GrAutoResourceCacheValidate(GrResourceCache*) {}