blob: 73d292442510f855849c6a7fff8c23504d87c596 [file] [log] [blame]
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#ifndef GrResourceCache_DEFINED
19#define GrResourceCache_DEFINED
20
21#include "GrTypes.h"
22#include "GrTHashCache.h"
23
24class GrResource;
25
26// return true if a<b, or false if b<a
27//
28#define RET_IF_LT_OR_GT(a, b) \
29 do { \
30 if ((a) < (b)) { \
31 return true; \
32 } \
33 if ((b) < (a)) { \
34 return false; \
35 } \
36 } while (0)
37
38/**
39 * Helper class for GrResourceCache, the Key is used to identify src data for
40 * a resource. It is identified by 2 32bit data fields which can hold any
41 * data (uninterpreted by the cache) and a width/height.
42 */
43class GrResourceKey {
44public:
45 enum {
46 kHashBits = 7,
47 kHashCount = 1 << kHashBits,
48 kHashMask = kHashCount - 1
49 };
50
51 GrResourceKey(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) {
52 fP[0] = p0;
53 fP[1] = p1;
54 fP[2] = p2;
55 fP[3] = p3;
56 this->computeHashIndex();
57 }
58
59 GrResourceKey(uint32_t v[4]) {
60 memcpy(fP, v, 4 * sizeof(uint32_t));
61 this->computeHashIndex();
62 }
63
64 GrResourceKey(const GrResourceKey& src) {
65 memcpy(fP, src.fP, 4 * sizeof(uint32_t));
66#if GR_DEBUG
67 this->computeHashIndex();
68 GrAssert(fHashIndex == src.fHashIndex);
69#endif
70 fHashIndex = src.fHashIndex;
71 }
72
73 //!< returns hash value [0..kHashMask] for the key
74 int hashIndex() const { return fHashIndex; }
75
76 friend bool operator==(const GrResourceKey& a, const GrResourceKey& b) {
77 GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex);
78 return 0 == memcmp(a.fP, b.fP, 4 * sizeof(uint32_t));
79 }
80
81 friend bool operator!=(const GrResourceKey& a, const GrResourceKey& b) {
82 GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex);
83 return !(a == b);
84 }
85
86 friend bool operator<(const GrResourceKey& a, const GrResourceKey& b) {
87 RET_IF_LT_OR_GT(a.fP[0], b.fP[0]);
88 RET_IF_LT_OR_GT(a.fP[1], b.fP[1]);
89 RET_IF_LT_OR_GT(a.fP[2], b.fP[2]);
90 return a.fP[3] < b.fP[3];
91 }
92
93 uint32_t getValue32(int i) const {
94 GrAssert(i >=0 && i < 4);
95 return fP[i];
96 }
97private:
98
99 static uint32_t rol(uint32_t x) {
100 return (x >> 24) | (x << 8);
101 }
102 static uint32_t ror(uint32_t x) {
103 return (x >> 8) | (x << 24);
104 }
105 static uint32_t rohalf(uint32_t x) {
106 return (x >> 16) | (x << 16);
107 }
108
109 void computeHashIndex() {
110 uint32_t hash = fP[0] ^ rol(fP[1]) ^ ror(fP[2]) ^ rohalf(fP[3]);
111 // this way to mix and reduce hash to its index may have to change
112 // depending on how many bits we allocate to the index
113 hash ^= hash >> 16;
114 hash ^= hash >> 8;
115 fHashIndex = hash & kHashMask;
116 }
117
118 uint32_t fP[4];
119
120 // this is computed from the fP... fields
121 int fHashIndex;
122
123 friend class GrContext;
124};
125
126///////////////////////////////////////////////////////////////////////////////
127
128class GrResourceEntry {
129public:
130 GrResource* resource() const { return fResource; }
131 const GrResourceKey& key() const { return fKey; }
132
133#if GR_DEBUG
134 GrResourceEntry* next() const { return fNext; }
135 GrResourceEntry* prev() const { return fPrev; }
136#endif
137
138#if GR_DEBUG
139 void validate() const;
140#else
141 void validate() const {}
142#endif
143
144private:
145 GrResourceEntry(const GrResourceKey& key, GrResource* resource);
146 ~GrResourceEntry();
147
148 bool isLocked() const { return fLockCount != 0; }
149 void lock() { ++fLockCount; }
150 void unlock() {
151 GrAssert(fLockCount > 0);
152 --fLockCount;
153 }
154
155 GrResourceKey fKey;
156 GrResource* fResource;
157
158 // track if we're in use, used when we need to purge
159 // we only purge unlocked entries
160 int fLockCount;
161
162 // we're a dlinklist
163 GrResourceEntry* fPrev;
164 GrResourceEntry* fNext;
165
166 friend class GrResourceCache;
167};
168
169///////////////////////////////////////////////////////////////////////////////
170
171#include "GrTHashCache.h"
172
173/**
174 * Cache of GrResource objects.
175 *
176 * These have a corresponding GrResourceKey, built from 128bits identifying the
177 * resource.
178 *
179 * The cache stores the entries in a double-linked list, which is its LRU.
180 * When an entry is "locked" (i.e. given to the caller), it is moved to the
181 * head of the list. If/when we must purge some of the entries, we walk the
182 * list backwards from the tail, since those are the least recently used.
183 *
184 * For fast searches, we maintain a sorted array (based on the GrResourceKey)
185 * which we can bsearch. When a new entry is added, it is inserted into this
186 * array.
187 *
188 * For even faster searches, a hash is computed from the Key. If there is
189 * a collision between two keys with the same hash, we fall back on the
190 * bsearch, and update the hash to reflect the most recent Key requested.
191 */
192class GrResourceCache {
193public:
194 GrResourceCache(int maxCount, size_t maxBytes);
195 ~GrResourceCache();
196
197 /**
198 * Return the current resource cache limits.
199 *
200 * @param maxResource If non-null, returns maximum number of resources
201 * that can be held in the cache.
202 * @param maxBytes If non-null, returns maximum number of bytes of
203 * gpu memory that can be held in the cache.
204 */
205 void getLimits(int* maxResources, size_t* maxBytes) const;
206
207 /**
208 * Specify the resource cache limits. If the current cache exceeds either
209 * of these, it will be purged (LRU) to keep the cache within these limits.
210 *
211 * @param maxResources The maximum number of resources that can be held in
212 * the cache.
213 * @param maxBytes The maximum number of bytes of resource memory that
214 * can be held in the cache.
215 */
216 void setLimits(int maxResource, size_t maxResourceBytes);
217
218 /**
219 * Search for an entry with the same Key. If found, "lock" it and return it.
220 * If not found, return null.
221 */
222 GrResourceEntry* findAndLock(const GrResourceKey&);
223
224 /**
225 * Create a new entry, based on the specified key and resource, and return
226 * its "locked" entry.
227 *
228 * Ownership of the resource is transferred to the Entry, which will unref()
229 * it when we are purged or deleted.
230 */
231 GrResourceEntry* createAndLock(const GrResourceKey&, GrResource*);
232
233 /**
234 * Detach removes an entry from the cache. This prevents the entry from
235 * being found by a subsequent findAndLock() until it is reattached. The
236 * entry still counts against the cache's budget and should be reattached
237 * when exclusive access is no longer needed.
238 */
239 void detach(GrResourceEntry*);
240
241 /**
242 * Reattaches a resource to the cache and unlocks it. Allows it to be found
243 * by a subsequent findAndLock or be purged (provided its lock count is
244 * now 0.)
245 */
246 void reattachAndUnlock(GrResourceEntry*);
247
248 /**
249 * When done with an entry, call unlock(entry) on it, which returns it to
250 * a purgable state.
251 */
252 void unlock(GrResourceEntry*);
253
254 void removeAll();
255
256#if GR_DEBUG
257 void validate() const;
258#else
259 void validate() const {}
260#endif
261
262private:
263 void internalDetach(GrResourceEntry*, bool);
264 void attachToHead(GrResourceEntry*, bool);
265 void purgeAsNeeded(); // uses kFreeResource_DeleteMode
266
267 class Key;
268 GrTHashTable<GrResourceEntry, Key, 8> fCache;
269
270 // manage the dlink list
271 GrResourceEntry* fHead;
272 GrResourceEntry* fTail;
273
274 // our budget, used in purgeAsNeeded()
275 int fMaxCount;
276 size_t fMaxBytes;
277
278 // our current stats, related to our budget
279 int fEntryCount;
280 size_t fEntryBytes;
281 int fClientDetachedCount;
282 size_t fClientDetachedBytes;
283};
284
285///////////////////////////////////////////////////////////////////////////////
286
287#if GR_DEBUG
288 class GrAutoResourceCacheValidate {
289 public:
290 GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
291 cache->validate();
292 }
293 ~GrAutoResourceCacheValidate() {
294 fCache->validate();
295 }
296 private:
297 GrResourceCache* fCache;
298 };
299#else
300 class GrAutoResourceCacheValidate {
301 public:
302 GrAutoResourceCacheValidate(GrResourceCache*) {}
303 };
304#endif
305
306#endif
307