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