• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     Copyright 2010 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 GrTextureCache_DEFINED
19 #define GrTextureCache_DEFINED
20 
21 #include "GrTypes.h"
22 #include "GrTHashCache.h"
23 
24 class GrTexture;
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 GrTextureCache, the Key is used to identify src data for
40  *  a texture. It is identified by 2 32bit data fields which can hold any
41  *  data (uninterpreted by the cache) and a width/height.
42  */
43 class GrTextureKey {
44 public:
45     enum {
46         kHashBits   = 7,
47         kHashCount  = 1 << kHashBits,
48         kHashMask   = kHashCount - 1
49     };
50 
GrTextureKey(uint32_t p0,uint32_t p1,uint16_t width,uint16_t height)51     GrTextureKey(uint32_t p0, uint32_t p1, uint16_t width, uint16_t height) {
52         fP0 = p0;
53         fP1 = p1;
54         fP2 = width | (height << 16);
55         GR_DEBUGCODE(fHashIndex = -1);
56     }
57 
GrTextureKey(const GrTextureKey & src)58     GrTextureKey(const GrTextureKey& src) {
59         fP0 = src.fP0;
60         fP1 = src.fP1;
61         fP2 = src.fP2;
62         finalize(src.fPrivateBits);
63     }
64 
65     //!< returns hash value [0..kHashMask] for the key
hashIndex()66     int hashIndex() const { return fHashIndex; }
67 
68     friend bool operator==(const GrTextureKey& a, const GrTextureKey& b) {
69         GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex);
70         return a.fP0 == b.fP0 && a.fP1 == b.fP1 && a.fP2 == b.fP2 &&
71                a.fPrivateBits == b.fPrivateBits;
72     }
73 
74     friend bool operator!=(const GrTextureKey& a, const GrTextureKey& b) {
75         GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex);
76         return !(a == b);
77     }
78 
79     friend bool operator<(const GrTextureKey& a, const GrTextureKey& b) {
80         RET_IF_LT_OR_GT(a.fP0, b.fP0);
81         RET_IF_LT_OR_GT(a.fP1, b.fP1);
82         RET_IF_LT_OR_GT(a.fP2, b.fP2);
83         return a.fPrivateBits < b.fPrivateBits;
84     }
85 
86 private:
finalize(uint32_t privateBits)87     void finalize(uint32_t privateBits) {
88         fPrivateBits = privateBits;
89         this->computeHashIndex();
90     }
91 
width()92     uint16_t width() const { return fP2 & 0xffff; }
height()93     uint16_t height() const { return (fP2 >> 16); }
94 
getPrivateBits()95     uint32_t getPrivateBits() const { return fPrivateBits; }
96 
rol(uint32_t x)97     static uint32_t rol(uint32_t x) {
98         return (x >> 24) | (x << 8);
99     }
ror(uint32_t x)100     static uint32_t ror(uint32_t x) {
101         return (x >> 8) | (x << 24);
102     }
rohalf(uint32_t x)103     static uint32_t rohalf(uint32_t x) {
104         return (x >> 16) | (x << 16);
105     }
106 
computeHashIndex()107     void computeHashIndex() {
108         uint32_t hash = fP0 ^ rol(fP1) ^ ror(fP2) ^ rohalf(fPrivateBits);
109         // this way to mix and reduce hash to its index may have to change
110         // depending on how many bits we allocate to the index
111         hash ^= hash >> 16;
112         hash ^= hash >> 8;
113         fHashIndex = hash & kHashMask;
114     }
115 
116     uint32_t    fP0;
117     uint32_t    fP1;
118     uint32_t    fP2;
119     uint32_t    fPrivateBits;
120 
121     // this is computed from the fP... fields
122     int         fHashIndex;
123 
124     friend class GrContext;
125 };
126 
127 ///////////////////////////////////////////////////////////////////////////////
128 
129 class GrTextureEntry {
130 public:
texture()131     GrTexture* texture() const { return fTexture; }
key()132     const GrTextureKey& key() const { return fKey; }
133 
134 #if GR_DEBUG
next()135     GrTextureEntry* next() const { return fNext; }
prev()136     GrTextureEntry* prev() const { return fPrev; }
137 #endif
138 
139 #if GR_DEBUG
140     void validate() const;
141 #else
validate()142     void validate() const {}
143 #endif
144 
145 private:
146     GrTextureEntry(const GrTextureKey& key, GrTexture* texture);
147     ~GrTextureEntry();
148 
isLocked()149     bool isLocked() const { return fLockCount != 0; }
lock()150     void lock() { ++fLockCount; }
unlock()151     void unlock() {
152         GrAssert(fLockCount > 0);
153         --fLockCount;
154     }
155 
156     GrTextureKey    fKey;
157     GrTexture*      fTexture;
158 
159     // track if we're in use, used when we need to purge
160     // we only purge unlocked entries
161     int fLockCount;
162 
163     // we're a dlinklist
164     GrTextureEntry* fPrev;
165     GrTextureEntry* fNext;
166 
167     friend class GrTextureCache;
168 };
169 
170 ///////////////////////////////////////////////////////////////////////////////
171 
172 #include "GrTHashCache.h"
173 
174 /**
175  *  Cache of GrTexture objects.
176  *
177  *  These have a corresponding GrTextureKey, built from 96bits identifying the
178  *  texture/bitmap.
179  *
180  *  The cache stores the entries in a double-linked list, which is its LRU.
181  *  When an entry is "locked" (i.e. given to the caller), it is moved to the
182  *  head of the list. If/when we must purge some of the entries, we walk the
183  *  list backwards from the tail, since those are the least recently used.
184  *
185  *  For fast searches, we maintain a sorted array (based on the GrTextureKey)
186  *  which we can bsearch. When a new entry is added, it is inserted into this
187  *  array.
188  *
189  *  For even faster searches, a hash is computed from the Key. If there is
190  *  a collision between two keys with the same hash, we fall back on the
191  *  bsearch, and update the hash to reflect the most recent Key requested.
192  */
193 class GrTextureCache {
194 public:
195     GrTextureCache(int maxCount, size_t maxBytes);
196     ~GrTextureCache();
197 
198     /**
199      *  Return the current texture cache limits.
200      *
201      *  @param maxTextures If non-null, returns maximum number of textures that
202      *                     can be held in the cache.
203      *  @param maxTextureBytes If non-null, returns maximum number of bytes of
204      *                         texture memory that can be held in the cache.
205      */
206     void getLimits(int* maxTextures, size_t* maxTextureBytes) const;
207 
208     /**
209      *  Specify the texture cache limits. If the current cache exceeds either
210      *  of these, it will be purged (LRU) to keep the cache within these limits.
211      *
212      *  @param maxTextures The maximum number of textures that can be held in
213      *                     the cache.
214      *  @param maxTextureBytes The maximum number of bytes of texture memory
215      *                         that can be held in the cache.
216      */
217     void setLimits(int maxTextures, size_t maxTextureBytes);
218 
219     /**
220      *  Search for an entry with the same Key. If found, "lock" it and return it.
221      *  If not found, return null.
222      */
223     GrTextureEntry* findAndLock(const GrTextureKey&);
224 
225     /**
226      *  Create a new entry, based on the specified key and texture, and return
227      *  its "locked" entry.
228      *
229      *  Ownership of the texture is transferred to the Entry, which will unref()
230      *  it when we are purged or deleted.
231      */
232     GrTextureEntry* createAndLock(const GrTextureKey&, GrTexture*);
233 
234     /**
235      * Detach removes an entry from the cache. This prevents the entry from
236      * being found by a subsequent findAndLock() until it is reattached. The
237      * entry still counts against the cache's budget and should be reattached
238      * when exclusive access is no longer needed.
239      */
240     void detach(GrTextureEntry*);
241 
242     /**
243      * Reattaches a texture to the cache and unlocks it. Allows it to be found
244      * by a subsequent findAndLock or be purged (provided its lock count is
245      * now 0.)
246      */
247     void reattachAndUnlock(GrTextureEntry*);
248 
249     /**
250      *  When done with an entry, call unlock(entry) on it, which returns it to
251      *  a purgable state.
252      */
253     void unlock(GrTextureEntry*);
254 
255     void removeAll();
256 
257 #if GR_DEBUG
258     void validate() const;
259 #else
validate()260     void validate() const {}
261 #endif
262 
263 private:
264     void internalDetach(GrTextureEntry*, bool);
265     void attachToHead(GrTextureEntry*, bool);
266     void purgeAsNeeded();   // uses kFreeTexture_DeleteMode
267 
268     class Key;
269     GrTHashTable<GrTextureEntry, Key, 8> fCache;
270 
271     // manage the dlink list
272     GrTextureEntry* fHead;
273     GrTextureEntry* fTail;
274 
275     // our budget, used in purgeAsNeeded()
276     int fMaxCount;
277     size_t fMaxBytes;
278 
279     // our current stats, related to our budget
280     int fEntryCount;
281     size_t fEntryBytes;
282     int fClientDetachedCount;
283     size_t fClientDetachedBytes;
284 };
285 
286 ///////////////////////////////////////////////////////////////////////////////
287 
288 #if GR_DEBUG
289     class GrAutoTextureCacheValidate {
290     public:
GrAutoTextureCacheValidate(GrTextureCache * cache)291         GrAutoTextureCacheValidate(GrTextureCache* cache) : fCache(cache) {
292             cache->validate();
293         }
~GrAutoTextureCacheValidate()294         ~GrAutoTextureCacheValidate() {
295             fCache->validate();
296         }
297     private:
298         GrTextureCache* fCache;
299     };
300 #else
301     class GrAutoTextureCacheValidate {
302     public:
GrAutoTextureCacheValidate(GrTextureCache *)303         GrAutoTextureCacheValidate(GrTextureCache*) {}
304     };
305 #endif
306 
307 #endif
308 
309