blob: 83337805a42f1c3a021f9ff61f4276b3cfe32316 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 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.
bsalomon@google.com50398bf2011-07-26 20:45:30 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
bsalomon@google.com50398bf2011-07-26 20:45:30 +000011#ifndef GrResourceCache_DEFINED
12#define GrResourceCache_DEFINED
13
bsalomon744998e2014-08-28 09:54:34 -070014#include "GrResourceKey.h"
robertphillips7a037f42014-07-21 12:40:57 -070015#include "SkTMultiMap.h"
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000016#include "SkMessageBus.h"
bsalomon@google.com42619d82012-12-03 14:54:59 +000017#include "SkTInternalLList.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018
bsalomon6d3fe022014-07-25 08:35:45 -070019class GrGpuResource;
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000020class GrResourceCache;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000021class GrResourceCacheEntry;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000022
bsalomon@google.com50398bf2011-07-26 20:45:30 +000023
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000024// The cache listens for these messages to purge junk resources proactively.
25struct GrResourceInvalidatedMessage {
26 GrResourceKey key;
27};
28
bsalomon@google.com50398bf2011-07-26 20:45:30 +000029///////////////////////////////////////////////////////////////////////////////
30
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000031class GrResourceCacheEntry {
bsalomon@google.com50398bf2011-07-26 20:45:30 +000032public:
bsalomon6d3fe022014-07-25 08:35:45 -070033 GrGpuResource* resource() const { return fResource; }
bsalomon@google.com50398bf2011-07-26 20:45:30 +000034 const GrResourceKey& key() const { return fKey; }
35
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000036 static const GrResourceKey& GetKey(const GrResourceCacheEntry& e) { return e.key(); }
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000037 static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000038#ifdef SK_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +000039 void validate() const;
40#else
41 void validate() const {}
42#endif
43
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000044 /**
45 * Update the cached size for this entry and inform the resource cache that
bsalomon6d3fe022014-07-25 08:35:45 -070046 * it has changed. Usually invoked from GrGpuResource::didChangeGpuMemorySize,
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000047 * not directly from here.
48 */
49 void didChangeResourceSize();
50
bsalomon@google.com50398bf2011-07-26 20:45:30 +000051private:
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000052 GrResourceCacheEntry(GrResourceCache* resourceCache,
53 const GrResourceKey& key,
bsalomon6d3fe022014-07-25 08:35:45 -070054 GrGpuResource* resource);
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000055 ~GrResourceCacheEntry();
bsalomon@google.com50398bf2011-07-26 20:45:30 +000056
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000057 GrResourceCache* fResourceCache;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000058 GrResourceKey fKey;
bsalomon6d3fe022014-07-25 08:35:45 -070059 GrGpuResource* fResource;
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000060 size_t fCachedSize;
61 bool fIsExclusive;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000062
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000063 // Linked list for the LRU ordering.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000064 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
bsalomon@google.com50398bf2011-07-26 20:45:30 +000065
66 friend class GrResourceCache;
bsalomon02e36f22014-08-22 12:01:46 -070067 friend class GrContext;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000068};
69
70///////////////////////////////////////////////////////////////////////////////
71
bsalomon@google.com50398bf2011-07-26 20:45:30 +000072/**
bsalomon6d3fe022014-07-25 08:35:45 -070073 * Cache of GrGpuResource objects.
bsalomon@google.com50398bf2011-07-26 20:45:30 +000074 *
75 * These have a corresponding GrResourceKey, built from 128bits identifying the
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000076 * resource. Multiple resources can map to same GrResourceKey.
bsalomon@google.com50398bf2011-07-26 20:45:30 +000077 *
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.
82 *
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000083 * For fast searches, we maintain a hash map based on the GrResourceKey.
bsalomon@google.com76202b82013-05-10 19:08:22 +000084 *
85 * It is a goal to make the GrResourceCache the central repository and bookkeeper
bsalomon6d3fe022014-07-25 08:35:45 -070086 * of all resources. It should replace the linked list of GrGpuResources that
bsalomon@google.com76202b82013-05-10 19:08:22 +000087 * GrGpu uses to call abandon/release.
bsalomon@google.com50398bf2011-07-26 20:45:30 +000088 */
89class GrResourceCache {
90public:
bsalomon@google.com07fc0d12012-06-22 15:15:59 +000091 GrResourceCache(int maxCount, size_t maxBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +000092 ~GrResourceCache();
93
94 /**
bsalomon@google.com07fc0d12012-06-22 15:15:59 +000095 * Return the current resource cache limits.
96 *
rmistry@google.comfbfcd562012-08-23 18:09:54 +000097 * @param maxResource If non-null, returns maximum number of resources
bsalomon@google.com07fc0d12012-06-22 15:15:59 +000098 * that can be held in the cache.
99 * @param maxBytes If non-null, returns maximum number of bytes of
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000100 * gpu memory that can be held in the cache.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000101 */
bsalomon@google.com07fc0d12012-06-22 15:15:59 +0000102 void getLimits(int* maxResources, size_t* maxBytes) const;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000103
104 /**
bsalomon@google.com07fc0d12012-06-22 15:15:59 +0000105 * 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.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000107 *
bsalomon@google.com07fc0d12012-06-22 15:15:59 +0000108 * @param maxResources The maximum number of resources that can be held in
109 * the cache.
110 * @param maxBytes The maximum number of bytes of resource memory that
111 * can be held in the cache.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000112 */
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000113 void setLimits(int maxResources, size_t maxResourceBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000114
115 /**
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000116 * The callback function used by the cache when it is still over budget
skia.committer@gmail.comde2e4e82013-07-11 07:01:01 +0000117 * after a purge. The passed in 'data' is the same 'data' handed to
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000118 * setOverbudgetCallback. The callback returns true if some resources
119 * have been freed.
120 */
121 typedef bool (*PFOverbudgetCB)(void* data);
122
123 /**
124 * Set the callback the cache should use when it is still over budget
skia.committer@gmail.comde2e4e82013-07-11 07:01:01 +0000125 * after a purge. The 'data' provided here will be passed back to the
skia.committer@gmail.com1f3c7382013-07-20 07:00:58 +0000126 * callback. Note that the cache will attempt to purge any resources newly
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000127 * freed by the callback.
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000128 */
129 void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
130 fOverbudgetCB = overbudgetCB;
131 fOverbudgetData = data;
132 }
133
134 /**
twiz@google.com05e70242012-01-27 19:12:00 +0000135 * Returns the number of bytes consumed by cached resources.
136 */
137 size_t getCachedResourceBytes() const { return fEntryBytes; }
138
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000139 /**
140 * Returns the number of cached resources.
141 */
142 int getCachedResourceCount() const { return fEntryCount; }
143
robertphillips@google.com209a1142012-10-31 12:25:21 +0000144 // 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
149 };
150
twiz@google.com05e70242012-01-27 19:12:00 +0000151 /**
robertphillips@google.coma9b06232012-08-30 11:06:31 +0000152 * Search for an entry with the same Key. If found, return it.
153 * If not found, return null.
skia.committer@gmail.comf3dc1992012-11-01 02:01:27 +0000154 * If ownershipFlags includes kNoOtherOwners and a resource is returned
robertphillips@google.com209a1142012-10-31 12:25:21 +0000155 * 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.
robertphillips@google.coma9b06232012-08-30 11:06:31 +0000161 */
bsalomon6d3fe022014-07-25 08:35:45 -0700162 GrGpuResource* find(const GrResourceKey& key,
163 uint32_t ownershipFlags = 0);
robertphillips@google.coma9b06232012-08-30 11:06:31 +0000164
165 /**
skia.committer@gmail.comf3dc1992012-11-01 02:01:27 +0000166 * Add the new resource to the cache (by creating a new cache entry based
167 * on the provided key and resource).
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000168 *
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000169 * Ownership of the resource is transferred to the resource cache,
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000170 * which will unref() it when it is purged or deleted.
robertphillips@google.com209a1142012-10-31 12:25:21 +0000171 *
172 * If ownershipFlags includes kHide, subsequent calls to 'find' will not
skia.committer@gmail.comf3dc1992012-11-01 02:01:27 +0000173 * return 'resource' until it is 'freed' (and recycled) or makeNonExclusive
robertphillips@google.com209a1142012-10-31 12:25:21 +0000174 * is called.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000175 */
skia.committer@gmail.comf3dc1992012-11-01 02:01:27 +0000176 void addResource(const GrResourceKey& key,
bsalomon6d3fe022014-07-25 08:35:45 -0700177 GrGpuResource* resource,
robertphillips@google.com209a1142012-10-31 12:25:21 +0000178 uint32_t ownershipFlags = 0);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000179
180 /**
bsalomon@google.comfb309512011-11-30 14:13:48 +0000181 * 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.
183 */
bsalomon49f085d2014-09-05 13:34:00 -0700184 bool hasKey(const GrResourceKey& key) const { return SkToBool(fCache.find(key)); }
bsalomon@google.comfb309512011-11-30 14:13:48 +0000185
186 /**
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000187 * 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.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191 */
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000192 void makeExclusive(GrResourceCacheEntry* entry);
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000193
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194 /**
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000195 * Restore 'entry' so that it can be found by future searches. 'entry'
196 * will also be purgeable (provided its lock count is now 0.)
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000197 */
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000198 void makeNonExclusive(GrResourceCacheEntry* entry);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199
200 /**
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +0000201 * Notify the cache that the size of a resource has changed.
202 */
203 void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc);
204 void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec);
205
206 /**
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000207 * Remove a resource from the cache and delete it!
208 */
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000209 void deleteResource(GrResourceCacheEntry* entry);
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000210
211 /**
bsalomon@google.coma2921122012-08-28 12:34:17 +0000212 * Removes every resource in the cache that isn't locked.
213 */
214 void purgeAllUnlocked();
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000215
robertphillips@google.com50a035d2012-09-07 19:44:33 +0000216 /**
217 * Allow cache to purge unused resources to obey resource limitations
robertphillips@google.com9fbcad02012-09-09 14:44:15 +0000218 * Note: this entry point will be hidden (again) once totally ref-driven
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000219 * cache maintenance is implemented. Note that the overbudget callback
220 * will be called if the initial purge doesn't get the cache under
221 * its budget.
robertphillips@google.com41d25322013-07-18 17:12:57 +0000222 *
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).
robertphillips@google.com50a035d2012-09-07 19:44:33 +0000226 */
robertphillips@google.com41d25322013-07-18 17:12:57 +0000227 void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
robertphillips@google.com50a035d2012-09-07 19:44:33 +0000228
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000229#ifdef SK_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000230 void validate() const;
231#else
232 void validate() const {}
233#endif
234
robertphillips@google.com59552022012-08-31 13:07:37 +0000235#if GR_CACHE_STATS
robertphillips@google.com9fbcad02012-09-09 14:44:15 +0000236 void printStats();
robertphillips@google.com59552022012-08-31 13:07:37 +0000237#endif
238
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000239private:
robertphillips@google.com209a1142012-10-31 12:25:21 +0000240 enum BudgetBehaviors {
241 kAccountFor_BudgetBehavior,
242 kIgnore_BudgetBehavior
243 };
244
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000245 void internalDetach(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
246 void attachToHead(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000247
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000248 void removeInvalidResource(GrResourceCacheEntry* entry);
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000249
robertphillips7a037f42014-07-21 12:40:57 -0700250 SkTMultiMap<GrResourceCacheEntry, GrResourceKey> fCache;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000251
bsalomon@google.com42619d82012-12-03 14:54:59 +0000252 // We're an internal doubly linked list
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000253 typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000254 EntryList fList;
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000255
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000256#ifdef SK_DEBUG
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000257 // These objects cannot be returned by a search
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000258 EntryList fExclusiveList;
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000259#endif
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000260
261 // our budget, used in purgeAsNeeded()
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000262 int fMaxCount;
263 size_t fMaxBytes;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000264
265 // our current stats, related to our budget
robertphillips@google.com59552022012-08-31 13:07:37 +0000266#if GR_CACHE_STATS
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000267 int fHighWaterEntryCount;
268 size_t fHighWaterEntryBytes;
269 int fHighWaterClientDetachedCount;
270 size_t fHighWaterClientDetachedBytes;
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +0000271#endif
272
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000273 int fEntryCount;
274 size_t fEntryBytes;
275 int fClientDetachedCount;
276 size_t fClientDetachedBytes;
robertphillips@google.com386319e2012-06-27 14:59:18 +0000277
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000278 // prevents recursive purging
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000279 bool fPurging;
280
281 PFOverbudgetCB fOverbudgetCB;
282 void* fOverbudgetData;
283
robertphillips@google.com41d25322013-07-18 17:12:57 +0000284 void internalPurge(int extraCount, size_t extraBytes);
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000285
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000286 // Listen for messages that a resource has been invalidated and purge cached junk proactively.
287 SkMessageBus<GrResourceInvalidatedMessage>::Inbox fInvalidationInbox;
288 void purgeInvalidated();
289
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000290#ifdef SK_DEBUG
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000291 static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000292#endif
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000293};
294
295///////////////////////////////////////////////////////////////////////////////
296
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000297#ifdef SK_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000298 class GrAutoResourceCacheValidate {
299 public:
300 GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
301 cache->validate();
302 }
303 ~GrAutoResourceCacheValidate() {
304 fCache->validate();
305 }
306 private:
307 GrResourceCache* fCache;
308 };
309#else
310 class GrAutoResourceCacheValidate {
311 public:
312 GrAutoResourceCacheValidate(GrResourceCache*) {}
313 };
314#endif
315
316#endif