blob: f6d064af395be1f44691c4d326efc676ca70db88 [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
bsalomon@google.com50398bf2011-07-26 20:45:30 +00009#ifndef GrResourceCache_DEFINED
10#define GrResourceCache_DEFINED
11
bsalomonbcf0a522014-10-08 08:40:09 -070012#include "GrDrawTargetCaps.h"
bsalomon744998e2014-08-28 09:54:34 -070013#include "GrResourceKey.h"
robertphillips7a037f42014-07-21 12:40:57 -070014#include "SkTMultiMap.h"
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000015#include "SkMessageBus.h"
bsalomon@google.com42619d82012-12-03 14:54:59 +000016#include "SkTInternalLList.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000017
bsalomon6d3fe022014-07-25 08:35:45 -070018class GrGpuResource;
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000019class GrResourceCache;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000020class GrResourceCacheEntry;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000021
bsalomon@google.com50398bf2011-07-26 20:45:30 +000022
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000023// The cache listens for these messages to purge junk resources proactively.
24struct GrResourceInvalidatedMessage {
25 GrResourceKey key;
26};
27
bsalomon@google.com50398bf2011-07-26 20:45:30 +000028///////////////////////////////////////////////////////////////////////////////
29
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000030class GrResourceCacheEntry {
bsalomon@google.com50398bf2011-07-26 20:45:30 +000031public:
bsalomon6d3fe022014-07-25 08:35:45 -070032 GrGpuResource* resource() const { return fResource; }
bsalomon@google.com50398bf2011-07-26 20:45:30 +000033 const GrResourceKey& key() const { return fKey; }
34
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000035 static const GrResourceKey& GetKey(const GrResourceCacheEntry& e) { return e.key(); }
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000036 static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +000037#ifdef SK_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +000038 void validate() const;
39#else
40 void validate() const {}
41#endif
42
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000043 /**
44 * Update the cached size for this entry and inform the resource cache that
bsalomon6d3fe022014-07-25 08:35:45 -070045 * it has changed. Usually invoked from GrGpuResource::didChangeGpuMemorySize,
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000046 * not directly from here.
47 */
48 void didChangeResourceSize();
49
bsalomon@google.com50398bf2011-07-26 20:45:30 +000050private:
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000051 GrResourceCacheEntry(GrResourceCache* resourceCache,
52 const GrResourceKey& key,
bsalomon6d3fe022014-07-25 08:35:45 -070053 GrGpuResource* resource);
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000054 ~GrResourceCacheEntry();
bsalomon@google.com50398bf2011-07-26 20:45:30 +000055
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000056 GrResourceCache* fResourceCache;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000057 GrResourceKey fKey;
bsalomon6d3fe022014-07-25 08:35:45 -070058 GrGpuResource* fResource;
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +000059 size_t fCachedSize;
60 bool fIsExclusive;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000061
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000062 // Linked list for the LRU ordering.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000063 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
bsalomon@google.com50398bf2011-07-26 20:45:30 +000064
65 friend class GrResourceCache;
bsalomon02e36f22014-08-22 12:01:46 -070066 friend class GrContext;
bsalomon@google.com50398bf2011-07-26 20:45:30 +000067};
68
69///////////////////////////////////////////////////////////////////////////////
70
bsalomon@google.com50398bf2011-07-26 20:45:30 +000071/**
bsalomon6d3fe022014-07-25 08:35:45 -070072 * Cache of GrGpuResource objects.
bsalomon@google.com50398bf2011-07-26 20:45:30 +000073 *
74 * These have a corresponding GrResourceKey, built from 128bits identifying the
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000075 * resource. Multiple resources can map to same GrResourceKey.
bsalomon@google.com50398bf2011-07-26 20:45:30 +000076 *
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.
81 *
commit-bot@chromium.orgbd58feb2014-01-17 17:56:21 +000082 * For fast searches, we maintain a hash map based on the GrResourceKey.
bsalomon@google.com76202b82013-05-10 19:08:22 +000083 *
84 * It is a goal to make the GrResourceCache the central repository and bookkeeper
bsalomon6d3fe022014-07-25 08:35:45 -070085 * of all resources. It should replace the linked list of GrGpuResources that
bsalomon@google.com76202b82013-05-10 19:08:22 +000086 * GrGpu uses to call abandon/release.
bsalomon@google.com50398bf2011-07-26 20:45:30 +000087 */
88class GrResourceCache {
89public:
bsalomonbcf0a522014-10-08 08:40:09 -070090 GrResourceCache(const GrDrawTargetCaps*, int maxCount, size_t maxBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +000091 ~GrResourceCache();
92
93 /**
bsalomon@google.com07fc0d12012-06-22 15:15:59 +000094 * Return the current resource cache limits.
95 *
rmistry@google.comfbfcd562012-08-23 18:09:54 +000096 * @param maxResource If non-null, returns maximum number of resources
bsalomon@google.com07fc0d12012-06-22 15:15:59 +000097 * that can be held in the cache.
98 * @param maxBytes If non-null, returns maximum number of bytes of
robertphillips@google.come4eaea22013-07-19 16:51:46 +000099 * gpu memory that can be held in the cache.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000100 */
bsalomon@google.com07fc0d12012-06-22 15:15:59 +0000101 void getLimits(int* maxResources, size_t* maxBytes) const;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000102
103 /**
bsalomon@google.com07fc0d12012-06-22 15:15:59 +0000104 * 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.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000106 *
bsalomon@google.com07fc0d12012-06-22 15:15:59 +0000107 * @param maxResources The maximum number of resources that can be held in
108 * the cache.
109 * @param maxBytes The maximum number of bytes of resource memory that
110 * can be held in the cache.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000111 */
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000112 void setLimits(int maxResources, size_t maxResourceBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000113
114 /**
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000115 * The callback function used by the cache when it is still over budget
skia.committer@gmail.comde2e4e82013-07-11 07:01:01 +0000116 * after a purge. The passed in 'data' is the same 'data' handed to
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000117 * setOverbudgetCallback. The callback returns true if some resources
118 * have been freed.
119 */
120 typedef bool (*PFOverbudgetCB)(void* data);
121
122 /**
123 * Set the callback the cache should use when it is still over budget
skia.committer@gmail.comde2e4e82013-07-11 07:01:01 +0000124 * after a purge. The 'data' provided here will be passed back to the
skia.committer@gmail.com1f3c7382013-07-20 07:00:58 +0000125 * callback. Note that the cache will attempt to purge any resources newly
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000126 * freed by the callback.
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000127 */
128 void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
129 fOverbudgetCB = overbudgetCB;
130 fOverbudgetData = data;
131 }
132
133 /**
twiz@google.com05e70242012-01-27 19:12:00 +0000134 * Returns the number of bytes consumed by cached resources.
135 */
136 size_t getCachedResourceBytes() const { return fEntryBytes; }
137
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000138 /**
139 * Returns the number of cached resources.
140 */
141 int getCachedResourceCount() const { return fEntryCount; }
142
twiz@google.com05e70242012-01-27 19:12:00 +0000143 /**
robertphillips@google.coma9b06232012-08-30 11:06:31 +0000144 * Search for an entry with the same Key. If found, return it.
145 * If not found, return null.
146 */
bsalomonbcf0a522014-10-08 08:40:09 -0700147 GrGpuResource* find(const GrResourceKey& key);
148
149 void makeResourceMRU(GrGpuResource*);
150
151 /** Called by GrGpuResources when they detects that they are newly purgable. */
152 void notifyPurgable(const GrGpuResource*);
robertphillips@google.coma9b06232012-08-30 11:06:31 +0000153
154 /**
skia.committer@gmail.comf3dc1992012-11-01 02:01:27 +0000155 * Add the new resource to the cache (by creating a new cache entry based
156 * on the provided key and resource).
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000157 *
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000158 * Ownership of the resource is transferred to the resource cache,
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000159 * which will unref() it when it is purged or deleted.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000160 */
bsalomonbcf0a522014-10-08 08:40:09 -0700161 void addResource(const GrResourceKey& key, GrGpuResource* resource);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000162
163 /**
bsalomon@google.comfb309512011-11-30 14:13:48 +0000164 * 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.
166 */
bsalomon49f085d2014-09-05 13:34:00 -0700167 bool hasKey(const GrResourceKey& key) const { return SkToBool(fCache.find(key)); }
bsalomon@google.comfb309512011-11-30 14:13:48 +0000168
169 /**
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +0000170 * Notify the cache that the size of a resource has changed.
171 */
172 void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc);
173 void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec);
174
175 /**
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000176 * Remove a resource from the cache and delete it!
177 */
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000178 void deleteResource(GrResourceCacheEntry* entry);
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000179
180 /**
bsalomon@google.coma2921122012-08-28 12:34:17 +0000181 * Removes every resource in the cache that isn't locked.
182 */
183 void purgeAllUnlocked();
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000184
robertphillips@google.com50a035d2012-09-07 19:44:33 +0000185 /**
186 * Allow cache to purge unused resources to obey resource limitations
robertphillips@google.com9fbcad02012-09-09 14:44:15 +0000187 * Note: this entry point will be hidden (again) once totally ref-driven
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000188 * cache maintenance is implemented. Note that the overbudget callback
189 * will be called if the initial purge doesn't get the cache under
190 * its budget.
robertphillips@google.com41d25322013-07-18 17:12:57 +0000191 *
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).
robertphillips@google.com50a035d2012-09-07 19:44:33 +0000195 */
robertphillips@google.com41d25322013-07-18 17:12:57 +0000196 void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
robertphillips@google.com50a035d2012-09-07 19:44:33 +0000197
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000198#ifdef SK_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199 void validate() const;
200#else
201 void validate() const {}
202#endif
203
robertphillips@google.com59552022012-08-31 13:07:37 +0000204#if GR_CACHE_STATS
robertphillips@google.com9fbcad02012-09-09 14:44:15 +0000205 void printStats();
robertphillips@google.com59552022012-08-31 13:07:37 +0000206#endif
207
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000208private:
bsalomonbcf0a522014-10-08 08:40:09 -0700209 void internalDetach(GrResourceCacheEntry*);
210 void attachToHead(GrResourceCacheEntry*);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000211 void purgeInvalidated();
bsalomonbcf0a522014-10-08 08:40:09 -0700212 void internalPurge(int extraCount, size_t extraBytes);
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000213#ifdef SK_DEBUG
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000214 static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000215#endif
bsalomonbcf0a522014-10-08 08:40:09 -0700216
217 typedef SkTMultiMap<GrResourceCacheEntry, GrResourceKey> CacheMap;
218 CacheMap fCache;
219
220 // We're an internal doubly linked list
221 typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
222 EntryList fList;
223
224 // our budget, used in purgeAsNeeded()
225 int fMaxCount;
226 size_t fMaxBytes;
227
228 // our current stats, related to our budget
229#if GR_CACHE_STATS
230 int fHighWaterEntryCount;
231 size_t fHighWaterEntryBytes;
232#endif
233
234 int fEntryCount;
235 size_t fEntryBytes;
236
237 // prevents recursive purging
238 bool fPurging;
239
240 PFOverbudgetCB fOverbudgetCB;
241 void* fOverbudgetData;
242
243 SkAutoTUnref<const GrDrawTargetCaps> fCaps;
244
245 // Listen for messages that a resource has been invalidated and purge cached junk proactively.
246 typedef SkMessageBus<GrResourceInvalidatedMessage>::Inbox Inbox;
247 Inbox fInvalidationInbox;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000248};
249
250///////////////////////////////////////////////////////////////////////////////
251
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000252#ifdef SK_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000253 class GrAutoResourceCacheValidate {
254 public:
255 GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
256 cache->validate();
257 }
258 ~GrAutoResourceCacheValidate() {
259 fCache->validate();
260 }
261 private:
262 GrResourceCache* fCache;
263 };
264#else
265 class GrAutoResourceCacheValidate {
266 public:
267 GrAutoResourceCacheValidate(GrResourceCache*) {}
268 };
269#endif
270
271#endif