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 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 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 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: 87 void finalize(uint32_t privateBits) { 88 fPrivateBits = privateBits; 89 this->computeHashIndex(); 90 } 91 92 uint16_t width() const { return fP2 & 0xffff; } 93 uint16_t height() const { return (fP2 >> 16); } 94 95 uint32_t getPrivateBits() const { return fPrivateBits; } 96 97 static uint32_t rol(uint32_t x) { 98 return (x >> 24) | (x << 8); 99 } 100 static uint32_t ror(uint32_t x) { 101 return (x >> 8) | (x << 24); 102 } 103 static uint32_t rohalf(uint32_t x) { 104 return (x >> 16) | (x << 16); 105 } 106 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: 131 GrTexture* texture() const { return fTexture; } 132 const GrTextureKey& key() const { return fKey; } 133 134 #if GR_DEBUG 135 GrTextureEntry* next() const { return fNext; } 136 GrTextureEntry* prev() const { return fPrev; } 137 #endif 138 139 #if GR_DEBUG 140 void validate() const; 141 #else 142 void validate() const {} 143 #endif 144 145 private: 146 GrTextureEntry(const GrTextureKey& key, GrTexture* texture); 147 ~GrTextureEntry(); 148 149 bool isLocked() const { return fLockCount != 0; } 150 void lock() { ++fLockCount; } 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 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: 291 GrAutoTextureCacheValidate(GrTextureCache* cache) : fCache(cache) { 292 cache->validate(); 293 } 294 ~GrAutoTextureCacheValidate() { 295 fCache->validate(); 296 } 297 private: 298 GrTextureCache* fCache; 299 }; 300 #else 301 class GrAutoTextureCacheValidate { 302 public: 303 GrAutoTextureCacheValidate(GrTextureCache*) {} 304 }; 305 #endif 306 307 #endif 308 309