1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkResourceCache_DEFINED 9 #define SkResourceCache_DEFINED 10 11 #include "SkBitmap.h" 12 13 class SkDiscardableMemory; 14 class SkMipMap; 15 16 /** 17 * Cache object for bitmaps (with possible scale in X Y as part of the key). 18 * 19 * Multiple caches can be instantiated, but each instance is not implicitly 20 * thread-safe, so if a given instance is to be shared across threads, the 21 * caller must manage the access itself (e.g. via a mutex). 22 * 23 * As a convenience, a global instance is also defined, which can be safely 24 * access across threads via the static methods (e.g. FindAndLock, etc.). 25 */ 26 class SkResourceCache { 27 public: 28 struct Key { 29 // Call this to access your private contents. Must not use the address after calling init() 30 void* writableContents() { return this + 1; } 31 32 // must call this after your private data has been written. 33 // length must be a multiple of 4 34 void init(size_t length); 35 36 // This is only valid after having called init(). 37 uint32_t hash() const { return fHash; } 38 39 bool operator==(const Key& other) const { 40 const uint32_t* a = this->as32(); 41 const uint32_t* b = other.as32(); 42 for (int i = 0; i < fCount32; ++i) { 43 if (a[i] != b[i]) { 44 return false; 45 } 46 } 47 return true; 48 } 49 50 private: 51 // store fCount32 first, so we don't consider it in operator< 52 int32_t fCount32; // 2 + user contents count32 53 uint32_t fHash; 54 /* uint32_t fContents32[] */ 55 56 const uint32_t* as32() const { return (const uint32_t*)this; } 57 const uint32_t* as32SkipCount() const { return this->as32() + 1; } 58 }; 59 60 struct Rec { 61 typedef SkResourceCache::Key Key; 62 63 Rec() {} 64 virtual ~Rec() {} 65 66 uint32_t getHash() const { return this->getKey().hash(); } 67 68 virtual const Key& getKey() const = 0; 69 virtual size_t bytesUsed() const = 0; 70 71 // for SkTDynamicHash::Traits 72 static uint32_t Hash(const Key& key) { return key.hash(); } 73 static const Key& GetKey(const Rec& rec) { return rec.getKey(); } 74 75 private: 76 Rec* fNext; 77 Rec* fPrev; 78 79 friend class SkResourceCache; 80 }; 81 82 typedef const Rec* ID; 83 84 /** 85 * Callback function for find(). If called, the cache will have found a match for the 86 * specified Key, and will pass in the corresponding Rec, along with a caller-specified 87 * context. The function can read the data in Rec, and copy whatever it likes into context 88 * (casting context to whatever it really is). 89 * 90 * The return value determines what the cache will do with the Rec. If the function returns 91 * true, then the Rec is considered "valid". If false is returned, the Rec will be considered 92 * "stale" and will be purged from the cache. 93 */ 94 typedef bool (*VisitorProc)(const Rec&, void* context); 95 96 /** 97 * Returns a locked/pinned SkDiscardableMemory instance for the specified 98 * number of bytes, or NULL on failure. 99 */ 100 typedef SkDiscardableMemory* (*DiscardableFactory)(size_t bytes); 101 102 /* 103 * The following static methods are thread-safe wrappers around a global 104 * instance of this cache. 105 */ 106 107 /** 108 * Returns true if the visitor was called on a matching Key, and the visitor returned true. 109 * 110 * Find() will search the cache for the specified Key. If no match is found, return false and 111 * do not call the VisitorProc. If a match is found, return whatever the visitor returns. 112 * Its return value is interpreted to mean: 113 * true : Rec is valid 114 * false : Rec is "stale" -- the cache will purge it. 115 */ 116 static bool Find(const Key& key, VisitorProc, void* context); 117 static void Add(Rec*); 118 119 static size_t GetTotalBytesUsed(); 120 static size_t GetTotalByteLimit(); 121 static size_t SetTotalByteLimit(size_t newLimit); 122 123 static size_t SetSingleAllocationByteLimit(size_t); 124 static size_t GetSingleAllocationByteLimit(); 125 126 static void PurgeAll(); 127 128 /** 129 * Returns the DiscardableFactory used by the global cache, or NULL. 130 */ 131 static DiscardableFactory GetDiscardableFactory(); 132 133 /** 134 * Use this allocator for bitmaps, so they can use ashmem when available. 135 * Returns NULL if the ResourceCache has not been initialized with a DiscardableFactory. 136 */ 137 static SkBitmap::Allocator* GetAllocator(); 138 139 /** 140 * Call SkDebugf() with diagnostic information about the state of the cache 141 */ 142 static void Dump(); 143 144 /////////////////////////////////////////////////////////////////////////// 145 146 /** 147 * Construct the cache to call DiscardableFactory when it 148 * allocates memory for the pixels. In this mode, the cache has 149 * not explicit budget, and so methods like getTotalBytesUsed() 150 * and getTotalByteLimit() will return 0, and setTotalByteLimit 151 * will ignore its argument and return 0. 152 */ 153 SkResourceCache(DiscardableFactory); 154 155 /** 156 * Construct the cache, allocating memory with malloc, and respect the 157 * byteLimit, purging automatically when a new image is added to the cache 158 * that pushes the total bytesUsed over the limit. Note: The limit can be 159 * changed at runtime with setTotalByteLimit. 160 */ 161 explicit SkResourceCache(size_t byteLimit); 162 ~SkResourceCache(); 163 164 /** 165 * Returns true if the visitor was called on a matching Key, and the visitor returned true. 166 * 167 * find() will search the cache for the specified Key. If no match is found, return false and 168 * do not call the VisitorProc. If a match is found, return whatever the visitor returns. 169 * Its return value is interpreted to mean: 170 * true : Rec is valid 171 * false : Rec is "stale" -- the cache will purge it. 172 */ 173 bool find(const Key&, VisitorProc, void* context); 174 void add(Rec*); 175 176 size_t getTotalBytesUsed() const { return fTotalBytesUsed; } 177 size_t getTotalByteLimit() const { return fTotalByteLimit; } 178 179 /** 180 * This is respected by SkBitmapProcState::possiblyScaleImage. 181 * 0 is no maximum at all; this is the default. 182 * setSingleAllocationByteLimit() returns the previous value. 183 */ 184 size_t setSingleAllocationByteLimit(size_t maximumAllocationSize); 185 size_t getSingleAllocationByteLimit() const; 186 /** 187 * Set the maximum number of bytes available to this cache. If the current 188 * cache exceeds this new value, it will be purged to try to fit within 189 * this new limit. 190 */ 191 size_t setTotalByteLimit(size_t newLimit); 192 193 void purgeAll() { 194 this->purgeAsNeeded(true); 195 } 196 197 DiscardableFactory discardableFactory() const { return fDiscardableFactory; } 198 SkBitmap::Allocator* allocator() const { return fAllocator; }; 199 200 /** 201 * Call SkDebugf() with diagnostic information about the state of the cache 202 */ 203 void dump() const; 204 205 private: 206 Rec* fHead; 207 Rec* fTail; 208 209 class Hash; 210 Hash* fHash; 211 212 DiscardableFactory fDiscardableFactory; 213 // the allocator is NULL or one that matches discardables 214 SkBitmap::Allocator* fAllocator; 215 216 size_t fTotalBytesUsed; 217 size_t fTotalByteLimit; 218 size_t fSingleAllocationByteLimit; 219 int fCount; 220 221 void purgeAsNeeded(bool forcePurge = false); 222 223 // linklist management 224 void moveToHead(Rec*); 225 void addToHead(Rec*); 226 void detach(Rec*); 227 void remove(Rec*); 228 229 void init(); // called by constructors 230 231 #ifdef SK_DEBUG 232 void validate() const; 233 #else 234 void validate() const {} 235 #endif 236 }; 237 #endif 238