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 #include "SkMessageBus.h" 13 #include "SkTDArray.h" 14 15 class SkCachedData; 16 class SkDiscardableMemory; 17 class SkMipMap; 18 19 /** 20 * Cache object for bitmaps (with possible scale in X Y as part of the key). 21 * 22 * Multiple caches can be instantiated, but each instance is not implicitly 23 * thread-safe, so if a given instance is to be shared across threads, the 24 * caller must manage the access itself (e.g. via a mutex). 25 * 26 * As a convenience, a global instance is also defined, which can be safely 27 * access across threads via the static methods (e.g. FindAndLock, etc.). 28 */ 29 class SkResourceCache { 30 public: 31 struct Key { 32 // Call this to access your private contents. Must not use the address after calling init() writableContentsKey33 void* writableContents() { return this + 1; } 34 35 // must call this after your private data has been written. 36 // nameSpace must be unique per Key subclass. 37 // sharedID == 0 means ignore this field : does not support group purging. 38 // length must be a multiple of 4 39 void init(void* nameSpace, uint64_t sharedID, size_t length); 40 getNamespaceKey41 void* getNamespace() const { return fNamespace; } getSharedIDKey42 uint64_t getSharedID() const { return ((uint64_t)fSharedID_hi << 32) | fSharedID_lo; } 43 44 // This is only valid after having called init(). hashKey45 uint32_t hash() const { return fHash; } 46 47 bool operator==(const Key& other) const { 48 const uint32_t* a = this->as32(); 49 const uint32_t* b = other.as32(); 50 for (int i = 0; i < fCount32; ++i) { // (This checks fCount == other.fCount first.) 51 if (a[i] != b[i]) { 52 return false; 53 } 54 } 55 return true; 56 } 57 58 private: 59 int32_t fCount32; // local + user contents count32 60 uint32_t fHash; 61 // split uint64_t into hi and lo so we don't force ourselves to pad on 32bit machines. 62 uint32_t fSharedID_lo; 63 uint32_t fSharedID_hi; 64 void* fNamespace; // A unique namespace tag. This is hashed. 65 /* uint32_t fContents32[] */ 66 as32Key67 const uint32_t* as32() const { return (const uint32_t*)this; } 68 }; 69 70 struct Rec { 71 typedef SkResourceCache::Key Key; 72 RecRec73 Rec() {} ~RecRec74 virtual ~Rec() {} 75 getHashRec76 uint32_t getHash() const { return this->getKey().hash(); } 77 78 virtual const Key& getKey() const = 0; 79 virtual size_t bytesUsed() const = 0; 80 81 // for SkTDynamicHash::Traits HashRec82 static uint32_t Hash(const Key& key) { return key.hash(); } GetKeyRec83 static const Key& GetKey(const Rec& rec) { return rec.getKey(); } 84 85 private: 86 Rec* fNext; 87 Rec* fPrev; 88 89 friend class SkResourceCache; 90 }; 91 92 // Used with SkMessageBus 93 struct PurgeSharedIDMessage { PurgeSharedIDMessagePurgeSharedIDMessage94 PurgeSharedIDMessage(uint64_t sharedID) : fSharedID(sharedID) {} 95 96 uint64_t fSharedID; 97 }; 98 99 typedef const Rec* ID; 100 101 /** 102 * Callback function for find(). If called, the cache will have found a match for the 103 * specified Key, and will pass in the corresponding Rec, along with a caller-specified 104 * context. The function can read the data in Rec, and copy whatever it likes into context 105 * (casting context to whatever it really is). 106 * 107 * The return value determines what the cache will do with the Rec. If the function returns 108 * true, then the Rec is considered "valid". If false is returned, the Rec will be considered 109 * "stale" and will be purged from the cache. 110 */ 111 typedef bool (*FindVisitor)(const Rec&, void* context); 112 113 /** 114 * Returns a locked/pinned SkDiscardableMemory instance for the specified 115 * number of bytes, or NULL on failure. 116 */ 117 typedef SkDiscardableMemory* (*DiscardableFactory)(size_t bytes); 118 119 /* 120 * The following static methods are thread-safe wrappers around a global 121 * instance of this cache. 122 */ 123 124 /** 125 * Returns true if the visitor was called on a matching Key, and the visitor returned true. 126 * 127 * Find() will search the cache for the specified Key. If no match is found, return false and 128 * do not call the FindVisitor. If a match is found, return whatever the visitor returns. 129 * Its return value is interpreted to mean: 130 * true : Rec is valid 131 * false : Rec is "stale" -- the cache will purge it. 132 */ 133 static bool Find(const Key& key, FindVisitor, void* context); 134 static void Add(Rec*); 135 136 static size_t GetTotalBytesUsed(); 137 static size_t GetTotalByteLimit(); 138 static size_t SetTotalByteLimit(size_t newLimit); 139 140 static size_t SetSingleAllocationByteLimit(size_t); 141 static size_t GetSingleAllocationByteLimit(); 142 static size_t GetEffectiveSingleAllocationByteLimit(); 143 144 static void PurgeAll(); 145 146 /** 147 * Returns the DiscardableFactory used by the global cache, or NULL. 148 */ 149 static DiscardableFactory GetDiscardableFactory(); 150 151 /** 152 * Use this allocator for bitmaps, so they can use ashmem when available. 153 * Returns NULL if the ResourceCache has not been initialized with a DiscardableFactory. 154 */ 155 static SkBitmap::Allocator* GetAllocator(); 156 157 static SkCachedData* NewCachedData(size_t bytes); 158 159 static void PostPurgeSharedID(uint64_t sharedID); 160 161 /** 162 * Call SkDebugf() with diagnostic information about the state of the cache 163 */ 164 static void Dump(); 165 166 /////////////////////////////////////////////////////////////////////////// 167 168 /** 169 * Construct the cache to call DiscardableFactory when it 170 * allocates memory for the pixels. In this mode, the cache has 171 * not explicit budget, and so methods like getTotalBytesUsed() 172 * and getTotalByteLimit() will return 0, and setTotalByteLimit 173 * will ignore its argument and return 0. 174 */ 175 SkResourceCache(DiscardableFactory); 176 177 /** 178 * Construct the cache, allocating memory with malloc, and respect the 179 * byteLimit, purging automatically when a new image is added to the cache 180 * that pushes the total bytesUsed over the limit. Note: The limit can be 181 * changed at runtime with setTotalByteLimit. 182 */ 183 explicit SkResourceCache(size_t byteLimit); 184 ~SkResourceCache(); 185 186 /** 187 * Returns true if the visitor was called on a matching Key, and the visitor returned true. 188 * 189 * find() will search the cache for the specified Key. If no match is found, return false and 190 * do not call the FindVisitor. If a match is found, return whatever the visitor returns. 191 * Its return value is interpreted to mean: 192 * true : Rec is valid 193 * false : Rec is "stale" -- the cache will purge it. 194 */ 195 bool find(const Key&, FindVisitor, void* context); 196 void add(Rec*); 197 getTotalBytesUsed()198 size_t getTotalBytesUsed() const { return fTotalBytesUsed; } getTotalByteLimit()199 size_t getTotalByteLimit() const { return fTotalByteLimit; } 200 201 /** 202 * This is respected by SkBitmapProcState::possiblyScaleImage. 203 * 0 is no maximum at all; this is the default. 204 * setSingleAllocationByteLimit() returns the previous value. 205 */ 206 size_t setSingleAllocationByteLimit(size_t maximumAllocationSize); 207 size_t getSingleAllocationByteLimit() const; 208 // returns the logical single allocation size (pinning against the budget when the cache 209 // is not backed by discardable memory. 210 size_t getEffectiveSingleAllocationByteLimit() const; 211 212 /** 213 * Set the maximum number of bytes available to this cache. If the current 214 * cache exceeds this new value, it will be purged to try to fit within 215 * this new limit. 216 */ 217 size_t setTotalByteLimit(size_t newLimit); 218 219 void purgeSharedID(uint64_t sharedID); 220 purgeAll()221 void purgeAll() { 222 this->purgeAsNeeded(true); 223 } 224 discardableFactory()225 DiscardableFactory discardableFactory() const { return fDiscardableFactory; } allocator()226 SkBitmap::Allocator* allocator() const { return fAllocator; }; 227 228 SkCachedData* newCachedData(size_t bytes); 229 230 /** 231 * Call SkDebugf() with diagnostic information about the state of the cache 232 */ 233 void dump() const; 234 235 private: 236 Rec* fHead; 237 Rec* fTail; 238 239 class Hash; 240 Hash* fHash; 241 242 DiscardableFactory fDiscardableFactory; 243 // the allocator is NULL or one that matches discardables 244 SkBitmap::Allocator* fAllocator; 245 246 size_t fTotalBytesUsed; 247 size_t fTotalByteLimit; 248 size_t fSingleAllocationByteLimit; 249 int fCount; 250 251 SkMessageBus<PurgeSharedIDMessage>::Inbox fPurgeSharedIDInbox; 252 253 void checkMessages(); 254 void purgeAsNeeded(bool forcePurge = false); 255 256 // linklist management 257 void moveToHead(Rec*); 258 void addToHead(Rec*); 259 void detach(Rec*); 260 void remove(Rec*); 261 262 void init(); // called by constructors 263 264 #ifdef SK_DEBUG 265 void validate() const; 266 #else validate()267 void validate() const {} 268 #endif 269 }; 270 #endif 271