Home | History | Annotate | Download | only in include
      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