blob: 880a0a98b5b5fc9811d480e1d08b7e74a9a7c12a [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
twiz@google.com05e70242012-01-27 19:12:00 +0000144 /**
robertphillips@google.coma9b06232012-08-30 11:06:31 +0000145 * Search for an entry with the same Key. If found, return it.
146 * If not found, return null.
147 */
bsalomond14e1a22014-10-07 07:27:07 -0700148 GrGpuResource* find(const GrResourceKey& key);
149
150 void makeResourceMRU(GrGpuResource*);
robertphillips@google.coma9b06232012-08-30 11:06:31 +0000151
152 /**
skia.committer@gmail.comf3dc1992012-11-01 02:01:27 +0000153 * Add the new resource to the cache (by creating a new cache entry based
154 * on the provided key and resource).
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000155 *
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000156 * Ownership of the resource is transferred to the resource cache,
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000157 * which will unref() it when it is purged or deleted.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000158 */
bsalomond14e1a22014-10-07 07:27:07 -0700159 void addResource(const GrResourceKey& key, GrGpuResource* resource);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000160
161 /**
bsalomon@google.comfb309512011-11-30 14:13:48 +0000162 * Determines if the cache contains an entry matching a key. If a matching
163 * entry exists but was detached then it will not be found.
164 */
bsalomon49f085d2014-09-05 13:34:00 -0700165 bool hasKey(const GrResourceKey& key) const { return SkToBool(fCache.find(key)); }
bsalomon@google.comfb309512011-11-30 14:13:48 +0000166
167 /**
commit-bot@chromium.org11c6b392014-05-05 19:09:13 +0000168 * Notify the cache that the size of a resource has changed.
169 */
170 void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc);
171 void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec);
172
173 /**
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000174 * Remove a resource from the cache and delete it!
175 */
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000176 void deleteResource(GrResourceCacheEntry* entry);
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000177
178 /**
bsalomon@google.coma2921122012-08-28 12:34:17 +0000179 * Removes every resource in the cache that isn't locked.
180 */
181 void purgeAllUnlocked();
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000182
robertphillips@google.com50a035d2012-09-07 19:44:33 +0000183 /**
184 * Allow cache to purge unused resources to obey resource limitations
robertphillips@google.com9fbcad02012-09-09 14:44:15 +0000185 * Note: this entry point will be hidden (again) once totally ref-driven
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000186 * cache maintenance is implemented. Note that the overbudget callback
187 * will be called if the initial purge doesn't get the cache under
188 * its budget.
robertphillips@google.com41d25322013-07-18 17:12:57 +0000189 *
190 * extraCount and extraBytes are added to the current resource allocation
191 * to make sure enough room is available for future additions (e.g,
192 * 10MB across 10 textures is about to be added).
robertphillips@google.com50a035d2012-09-07 19:44:33 +0000193 */
robertphillips@google.com41d25322013-07-18 17:12:57 +0000194 void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
robertphillips@google.com50a035d2012-09-07 19:44:33 +0000195
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000196#ifdef SK_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000197 void validate() const;
198#else
199 void validate() const {}
200#endif
201
robertphillips@google.com59552022012-08-31 13:07:37 +0000202#if GR_CACHE_STATS
robertphillips@google.com9fbcad02012-09-09 14:44:15 +0000203 void printStats();
robertphillips@google.com59552022012-08-31 13:07:37 +0000204#endif
205
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000206private:
bsalomond14e1a22014-10-07 07:27:07 -0700207 void internalDetach(GrResourceCacheEntry*);
208 void attachToHead(GrResourceCacheEntry*);
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000209
robertphillips7a037f42014-07-21 12:40:57 -0700210 SkTMultiMap<GrResourceCacheEntry, GrResourceKey> fCache;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000211
bsalomon@google.com42619d82012-12-03 14:54:59 +0000212 // We're an internal doubly linked list
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000213 typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000214 EntryList fList;
robertphillips@google.com521eaf82012-08-22 11:03:19 +0000215
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000216 // our budget, used in purgeAsNeeded()
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000217 int fMaxCount;
218 size_t fMaxBytes;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000219
220 // our current stats, related to our budget
robertphillips@google.com59552022012-08-31 13:07:37 +0000221#if GR_CACHE_STATS
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000222 int fHighWaterEntryCount;
223 size_t fHighWaterEntryBytes;
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +0000224#endif
225
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000226 int fEntryCount;
227 size_t fEntryBytes;
robertphillips@google.com386319e2012-06-27 14:59:18 +0000228
bsalomon@google.coma5a1da82011-08-05 14:02:41 +0000229 // prevents recursive purging
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000230 bool fPurging;
231
232 PFOverbudgetCB fOverbudgetCB;
233 void* fOverbudgetData;
234
robertphillips@google.com41d25322013-07-18 17:12:57 +0000235 void internalPurge(int extraCount, size_t extraBytes);
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000236
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000237 // Listen for messages that a resource has been invalidated and purge cached junk proactively.
238 SkMessageBus<GrResourceInvalidatedMessage>::Inbox fInvalidationInbox;
239 void purgeInvalidated();
240
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000241#ifdef SK_DEBUG
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000242 static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000243#endif
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000244};
245
246///////////////////////////////////////////////////////////////////////////////
247
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000248#ifdef SK_DEBUG
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000249 class GrAutoResourceCacheValidate {
250 public:
251 GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
252 cache->validate();
253 }
254 ~GrAutoResourceCacheValidate() {
255 fCache->validate();
256 }
257 private:
258 GrResourceCache* fCache;
259 };
260#else
261 class GrAutoResourceCacheValidate {
262 public:
263 GrAutoResourceCacheValidate(GrResourceCache*) {}
264 };
265#endif
266
267#endif