| epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 1 |  | 
|  | 2 | /* | 
|  | 3 | * 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. | 
|  | 7 | */ | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 8 | #ifndef SkTextureCache_DEFINED | 
|  | 9 | #define SkTextureCache_DEFINED | 
|  | 10 |  | 
|  | 11 | #include "SkBitmap.h" | 
|  | 12 | #include "SkPoint.h" | 
|  | 13 | #include "SkGL.h" | 
|  | 14 | #include "SkTDArray.h" | 
|  | 15 |  | 
|  | 16 | class SkTextureCache { | 
|  | 17 | public: | 
|  | 18 | SkTextureCache(size_t maxCount, size_t maxSize); | 
|  | 19 | ~SkTextureCache(); | 
|  | 20 |  | 
|  | 21 | size_t getMaxCount() { return fTexCountMax; } | 
|  | 22 | size_t getMaxSize() { return fTexSizeMax; } | 
|  | 23 |  | 
|  | 24 | void setMaxCount(size_t count); | 
|  | 25 | void setMaxSize(size_t size); | 
|  | 26 |  | 
|  | 27 | /** Deletes all the caches. Pass true if the texture IDs are still valid, | 
|  | 28 | and if so, it will call glDeleteTextures. Pass false if the texture IDs | 
|  | 29 | are invalid (e.g. the gl-context has changed), in which case they will | 
|  | 30 | just be abandoned. | 
|  | 31 | */ | 
|  | 32 | void deleteAllCaches(bool texturesAreValid); | 
|  | 33 |  | 
|  | 34 | static int HashMask() { return kHashMask; } | 
|  | 35 |  | 
|  | 36 | class Key { | 
|  | 37 | public: | 
|  | 38 | Key(const SkBitmap& bm) { | 
|  | 39 | fGenID = bm.getGenerationID(); | 
|  | 40 | fOffset = bm.pixelRefOffset(); | 
|  | 41 | fWH = (bm.width() << 16) | bm.height(); | 
|  | 42 | this->computeHash(); | 
|  | 43 | } | 
|  | 44 |  | 
|  | 45 | int getHashIndex() const { return fHashIndex; } | 
|  | 46 |  | 
|  | 47 | friend bool operator==(const Key& a, const Key& b) { | 
|  | 48 | return  a.fHash ==   b.fHash && | 
|  | 49 | a.fGenID ==  b.fGenID && | 
|  | 50 | a.fOffset == b.fOffset && | 
|  | 51 | a.fWH ==     b.fWH; | 
|  | 52 | } | 
|  | 53 |  | 
|  | 54 | friend bool operator<(const Key& a, const Key& b) { | 
|  | 55 | if (a.fHash < b.fHash) { | 
|  | 56 | return true; | 
|  | 57 | } else if (a.fHash > b.fHash) { | 
|  | 58 | return false; | 
|  | 59 | } | 
|  | 60 |  | 
|  | 61 | if (a.fGenID < b.fGenID) { | 
|  | 62 | return true; | 
|  | 63 | } else if (a.fGenID > b.fGenID) { | 
|  | 64 | return false; | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 | if (a.fOffset < b.fOffset) { | 
|  | 68 | return true; | 
|  | 69 | } else if (a.fOffset > b.fOffset) { | 
|  | 70 | return false; | 
|  | 71 | } | 
|  | 72 |  | 
|  | 73 | return a.fWH < b.fWH; | 
|  | 74 | } | 
|  | 75 |  | 
|  | 76 | private: | 
|  | 77 | void computeHash() { | 
|  | 78 | uint32_t hash = fGenID ^ fOffset ^ fWH; | 
|  | 79 | fHash = hash; | 
|  | 80 | hash ^= hash >> 16; | 
|  | 81 | fHashIndex = hash & SkTextureCache::HashMask(); | 
|  | 82 | } | 
|  | 83 |  | 
|  | 84 | uint32_t    fHash;  // computed from the other fields | 
|  | 85 | uint32_t    fGenID; | 
|  | 86 | size_t      fOffset; | 
|  | 87 | uint32_t    fWH; | 
|  | 88 | // for indexing into the texturecache's fHash | 
|  | 89 | int fHashIndex; | 
|  | 90 | }; | 
|  | 91 |  | 
|  | 92 | class Entry { | 
|  | 93 | public: | 
|  | 94 | GLuint name() const { return fName; } | 
|  | 95 | SkPoint texSize() const { return fTexSize; } | 
|  | 96 | size_t memSize() const { return fMemSize; } | 
|  | 97 | const Key& getKey() const { return fKey; } | 
|  | 98 |  | 
|  | 99 | // call this to clear the texture name, in case the context has changed | 
|  | 100 | // in which case we should't reference or delete this texture in GL | 
|  | 101 | void abandonTexture() { fName = 0; } | 
|  | 102 |  | 
|  | 103 | private: | 
|  | 104 | Entry(const SkBitmap& bitmap); | 
|  | 105 | ~Entry(); | 
|  | 106 |  | 
|  | 107 | int lockCount() const { return fLockCount; } | 
|  | 108 | bool isLocked() const { return fLockCount > 0; } | 
|  | 109 |  | 
|  | 110 | void lock() { fLockCount += 1; } | 
|  | 111 | void unlock() { | 
|  | 112 | SkASSERT(fLockCount > 0); | 
|  | 113 | fLockCount -= 1; | 
|  | 114 | } | 
|  | 115 |  | 
|  | 116 | private: | 
|  | 117 | GLuint  fName; | 
|  | 118 | SkPoint fTexSize; | 
|  | 119 | Key     fKey; | 
|  | 120 | size_t  fMemSize; | 
|  | 121 | int     fLockCount; | 
|  | 122 |  | 
|  | 123 | Entry*  fPrev; | 
|  | 124 | Entry*  fNext; | 
|  | 125 |  | 
|  | 126 | friend class SkTextureCache; | 
|  | 127 | }; | 
|  | 128 |  | 
|  | 129 | Entry* lock(const SkBitmap&); | 
|  | 130 | void unlock(Entry*); | 
|  | 131 |  | 
|  | 132 | private: | 
|  | 133 | void purgeIfNecessary(size_t extraSize); | 
|  | 134 |  | 
|  | 135 | #ifdef SK_DEBUG | 
|  | 136 | void validate() const; | 
|  | 137 | #else | 
|  | 138 | void validate() const {} | 
|  | 139 | #endif | 
|  | 140 |  | 
|  | 141 | Entry* fHead; | 
|  | 142 | Entry* fTail; | 
|  | 143 |  | 
|  | 144 | // limits for the cache | 
|  | 145 | size_t  fTexCountMax; | 
|  | 146 | size_t  fTexSizeMax; | 
|  | 147 |  | 
|  | 148 | // current values for the cache | 
|  | 149 | size_t  fTexCount; | 
|  | 150 | size_t  fTexSize; | 
|  | 151 |  | 
|  | 152 | enum { | 
|  | 153 | kHashBits = 6, | 
|  | 154 | kHashCount = 1 << kHashBits, | 
|  | 155 | kHashMask = kHashCount - 1 | 
|  | 156 | }; | 
|  | 157 | mutable Entry* fHash[kHashCount]; | 
|  | 158 | SkTDArray<Entry*> fSorted; | 
|  | 159 |  | 
|  | 160 | /*  If we find the key, return the entry and ignore index. If we don't, | 
|  | 161 | return NULL and set index to the place to insert the entry in fSorted | 
|  | 162 | */ | 
|  | 163 | Entry* find(const Key&, int* index) const; | 
|  | 164 | // returns index or <0 if not found. Does NOT update hash | 
|  | 165 | int findInSorted(const Key& key) const; | 
|  | 166 | }; | 
|  | 167 |  | 
|  | 168 | #endif |