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.
9 #ifndef GrResourceCache_DEFINED
10 #define GrResourceCache_DEFINED
12 #include "GrDrawTargetCaps.h"
13 #include "GrResourceKey.h"
14 #include "SkTMultiMap.h"
15 #include "SkMessageBus.h"
16 #include "SkTInternalLList.h"
19 class GrResourceCache;
20 class GrResourceCacheEntry;
23 // The cache listens for these messages to purge junk resources proactively.
24 struct GrResourceInvalidatedMessage {
28 ///////////////////////////////////////////////////////////////////////////////
30 class GrResourceCacheEntry {
32 GrGpuResource* resource() const { return fResource; }
33 const GrResourceKey& key() const { return fKey; }
35 static const GrResourceKey& GetKey(const GrResourceCacheEntry& e) { return e.key(); }
36 static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
38 void validate() const;
40 void validate() const {}
44 * Update the cached size for this entry and inform the resource cache that
45 * it has changed. Usually invoked from GrGpuResource::didChangeGpuMemorySize,
46 * not directly from here.
48 void didChangeResourceSize();
51 GrResourceCacheEntry(GrResourceCache* resourceCache,
52 const GrResourceKey& key,
53 GrGpuResource* resource);
54 ~GrResourceCacheEntry();
56 GrResourceCache* fResourceCache;
58 GrGpuResource* fResource;
62 // Linked list for the LRU ordering.
63 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
65 friend class GrResourceCache;
66 friend class GrContext;
69 ///////////////////////////////////////////////////////////////////////////////
72 * Cache of GrGpuResource objects.
74 * These have a corresponding GrResourceKey, built from 128bits identifying the
75 * resource. Multiple resources can map to same GrResourceKey.
77 * The cache stores the entries in a double-linked list, which is its LRU.
78 * When an entry is "locked" (i.e. given to the caller), it is moved to the
79 * head of the list. If/when we must purge some of the entries, we walk the
80 * list backwards from the tail, since those are the least recently used.
82 * For fast searches, we maintain a hash map based on the GrResourceKey.
84 * It is a goal to make the GrResourceCache the central repository and bookkeeper
85 * of all resources. It should replace the linked list of GrGpuResources that
86 * GrGpu uses to call abandon/release.
88 class GrResourceCache {
90 GrResourceCache(const GrDrawTargetCaps*, int maxCount, size_t maxBytes);
94 * Return the current resource cache limits.
96 * @param maxResource If non-null, returns maximum number of resources
97 * that can be held in the cache.
98 * @param maxBytes If non-null, returns maximum number of bytes of
99 * gpu memory that can be held in the cache.
101 void getLimits(int* maxResources, size_t* maxBytes) const;
104 * Specify the resource cache limits. If the current cache exceeds either
105 * of these, it will be purged (LRU) to keep the cache within these limits.
107 * @param maxResources The maximum number of resources that can be held in
109 * @param maxBytes The maximum number of bytes of resource memory that
110 * can be held in the cache.
112 void setLimits(int maxResources, size_t maxResourceBytes);
115 * The callback function used by the cache when it is still over budget
116 * after a purge. The passed in 'data' is the same 'data' handed to
117 * setOverbudgetCallback. The callback returns true if some resources
120 typedef bool (*PFOverbudgetCB)(void* data);
123 * Set the callback the cache should use when it is still over budget
124 * after a purge. The 'data' provided here will be passed back to the
125 * callback. Note that the cache will attempt to purge any resources newly
126 * freed by the callback.
128 void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
129 fOverbudgetCB = overbudgetCB;
130 fOverbudgetData = data;
134 * Returns the number of bytes consumed by cached resources.
136 size_t getCachedResourceBytes() const { return fEntryBytes; }
139 * Returns the number of cached resources.
141 int getCachedResourceCount() const { return fEntryCount; }
144 * Search for an entry with the same Key. If found, return it.
145 * If not found, return null.
147 GrGpuResource* find(const GrResourceKey& key);
149 void makeResourceMRU(GrGpuResource*);
151 /** Called by GrGpuResources when they detects that they are newly purgable. */
152 void notifyPurgable(const GrGpuResource*);
155 * Add the new resource to the cache (by creating a new cache entry based
156 * on the provided key and resource).
158 * Ownership of the resource is transferred to the resource cache,
159 * which will unref() it when it is purged or deleted.
161 void addResource(const GrResourceKey& key, GrGpuResource* resource);
164 * Determines if the cache contains an entry matching a key. If a matching
165 * entry exists but was detached then it will not be found.
167 bool hasKey(const GrResourceKey& key) const { return SkToBool(fCache.find(key)); }
170 * Notify the cache that the size of a resource has changed.
172 void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc);
173 void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec);
176 * Remove a resource from the cache and delete it!
178 void deleteResource(GrResourceCacheEntry* entry);
181 * Removes every resource in the cache that isn't locked.
183 void purgeAllUnlocked();
186 * Allow cache to purge unused resources to obey resource limitations
187 * Note: this entry point will be hidden (again) once totally ref-driven
188 * cache maintenance is implemented. Note that the overbudget callback
189 * will be called if the initial purge doesn't get the cache under
192 * extraCount and extraBytes are added to the current resource allocation
193 * to make sure enough room is available for future additions (e.g,
194 * 10MB across 10 textures is about to be added).
196 void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
199 void validate() const;
201 void validate() const {}
209 void internalDetach(GrResourceCacheEntry*);
210 void attachToHead(GrResourceCacheEntry*);
211 void purgeInvalidated();
212 void internalPurge(int extraCount, size_t extraBytes);
214 static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
217 typedef SkTMultiMap<GrResourceCacheEntry, GrResourceKey> CacheMap;
220 // We're an internal doubly linked list
221 typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
224 // our budget, used in purgeAsNeeded()
228 // our current stats, related to our budget
230 int fHighWaterEntryCount;
231 size_t fHighWaterEntryBytes;
237 // prevents recursive purging
240 PFOverbudgetCB fOverbudgetCB;
241 void* fOverbudgetData;
243 SkAutoTUnref<const GrDrawTargetCaps> fCaps;
245 // Listen for messages that a resource has been invalidated and purge cached junk proactively.
246 typedef SkMessageBus<GrResourceInvalidatedMessage>::Inbox Inbox;
247 Inbox fInvalidationInbox;
250 ///////////////////////////////////////////////////////////////////////////////
253 class GrAutoResourceCacheValidate {
255 GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
258 ~GrAutoResourceCacheValidate() {
262 GrResourceCache* fCache;
265 class GrAutoResourceCacheValidate {
267 GrAutoResourceCacheValidate(GrResourceCache*) {}