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 SkScaledImageCache_DEFINED 9 #define SkScaledImageCache_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 SkScaledImageCache { 27 public: 28 struct ID; 29 30 /** 31 * Returns a locked/pinned SkDiscardableMemory instance for the specified 32 * number of bytes, or NULL on failure. 33 */ 34 typedef SkDiscardableMemory* (*DiscardableFactory)(size_t bytes); 35 36 /* 37 * The following static methods are thread-safe wrappers around a global 38 * instance of this cache. 39 */ 40 41 static ID* FindAndLock(uint32_t pixelGenerationID, 42 int32_t width, 43 int32_t height, 44 SkBitmap* returnedBitmap); 45 46 static ID* FindAndLock(const SkBitmap& original, SkScalar scaleX, 47 SkScalar scaleY, SkBitmap* returnedBitmap); 48 static ID* FindAndLockMip(const SkBitmap& original, 49 SkMipMap const** returnedMipMap); 50 51 52 static ID* AddAndLock(uint32_t pixelGenerationID, 53 int32_t width, 54 int32_t height, 55 const SkBitmap& bitmap); 56 57 static ID* AddAndLock(const SkBitmap& original, SkScalar scaleX, 58 SkScalar scaleY, const SkBitmap& bitmap); 59 static ID* AddAndLockMip(const SkBitmap& original, const SkMipMap* mipMap); 60 61 static void Unlock(ID*); 62 63 static size_t GetBytesUsed(); 64 static size_t GetByteLimit(); 65 static size_t SetByteLimit(size_t newLimit); 66 67 static SkBitmap::Allocator* GetAllocator(); 68 69 /** 70 * Call SkDebugf() with diagnostic information about the state of the cache 71 */ 72 static void Dump(); 73 74 /////////////////////////////////////////////////////////////////////////// 75 76 /** 77 * Construct the cache to call DiscardableFactory when it 78 * allocates memory for the pixels. In this mode, the cache has 79 * not explicit budget, and so methods like getBytesUsed() and 80 * getByteLimit() will return 0, and setByteLimit will ignore its argument 81 * and return 0. 82 */ 83 SkScaledImageCache(DiscardableFactory); 84 85 /** 86 * Construct the cache, allocating memory with malloc, and respect the 87 * byteLimit, purging automatically when a new image is added to the cache 88 * that pushes the total bytesUsed over the limit. Note: The limit can be 89 * changed at runtime with setByteLimit. 90 */ 91 SkScaledImageCache(size_t byteLimit); 92 93 ~SkScaledImageCache(); 94 95 /** 96 * Search the cache for a matching bitmap (using generationID, 97 * width, and height as a search key). If found, return it in 98 * returnedBitmap, and return its ID pointer. Use the returned 99 * ptr to unlock the cache when you are done using 100 * returnedBitmap. 101 * 102 * If a match is not found, returnedBitmap will be unmodifed, and 103 * NULL will be returned. 104 * 105 * This is used if there is no scaling or subsetting, for example 106 * by SkLazyPixelRef. 107 */ 108 ID* findAndLock(uint32_t pixelGenerationID, int32_t width, int32_t height, 109 SkBitmap* returnedBitmap); 110 111 /** 112 * Search the cache for a scaled version of original. If found, 113 * return it in returnedBitmap, and return its ID pointer. Use 114 * the returned ptr to unlock the cache when you are done using 115 * returnedBitmap. 116 * 117 * If a match is not found, returnedBitmap will be unmodifed, and 118 * NULL will be returned. 119 */ 120 ID* findAndLock(const SkBitmap& original, SkScalar scaleX, 121 SkScalar scaleY, SkBitmap* returnedBitmap); 122 ID* findAndLockMip(const SkBitmap& original, 123 SkMipMap const** returnedMipMap); 124 125 /** 126 * To add a new bitmap (or mipMap) to the cache, call 127 * AddAndLock. Use the returned ptr to unlock the cache when you 128 * are done using scaled. 129 * 130 * Use (generationID, width, and height) or (original, scaleX, 131 * scaleY) or (original) as a search key 132 */ 133 ID* addAndLock(uint32_t pixelGenerationID, int32_t width, int32_t height, 134 const SkBitmap& bitmap); 135 ID* addAndLock(const SkBitmap& original, SkScalar scaleX, 136 SkScalar scaleY, const SkBitmap& bitmap); 137 ID* addAndLockMip(const SkBitmap& original, const SkMipMap* mipMap); 138 139 /** 140 * Given a non-null ID ptr returned by either findAndLock or addAndLock, 141 * this releases the associated resources to be available to be purged 142 * if needed. After this, the cached bitmap should no longer be 143 * referenced by the caller. 144 */ 145 void unlock(ID*); 146 getBytesUsed()147 size_t getBytesUsed() const { return fBytesUsed; } getByteLimit()148 size_t getByteLimit() const { return fByteLimit; } 149 150 /** 151 * Set the maximum number of bytes available to this cache. If the current 152 * cache exceeds this new value, it will be purged to try to fit within 153 * this new limit. 154 */ 155 size_t setByteLimit(size_t newLimit); 156 allocator()157 SkBitmap::Allocator* allocator() const { return fAllocator; }; 158 159 /** 160 * Call SkDebugf() with diagnostic information about the state of the cache 161 */ 162 void dump() const; 163 164 public: 165 struct Rec; 166 struct Key; 167 private: 168 Rec* fHead; 169 Rec* fTail; 170 171 class Hash; 172 Hash* fHash; 173 174 DiscardableFactory fDiscardableFactory; 175 // the allocator is NULL or one that matches discardables 176 SkBitmap::Allocator* fAllocator; 177 178 size_t fBytesUsed; 179 size_t fByteLimit; 180 int fCount; 181 182 Rec* findAndLock(uint32_t generationID, SkScalar sx, SkScalar sy, 183 const SkIRect& bounds); 184 Rec* findAndLock(const Key& key); 185 ID* addAndLock(Rec* rec); 186 187 void purgeRec(Rec*); 188 void purgeAsNeeded(); 189 190 // linklist management 191 void moveToHead(Rec*); 192 void addToHead(Rec*); 193 void detach(Rec*); 194 195 void init(); // called by constructors 196 197 #ifdef SK_DEBUG 198 void validate() const; 199 #else validate()200 void validate() const {} 201 #endif 202 }; 203 #endif 204