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 GetTotalBytesUsed(); 64 static size_t GetTotalByteLimit(); 65 static size_t SetTotalByteLimit(size_t newLimit); 66 67 static size_t SetSingleAllocationByteLimit(size_t); 68 static size_t GetSingleAllocationByteLimit(); 69 70 static SkBitmap::Allocator* GetAllocator(); 71 72 /** 73 * Call SkDebugf() with diagnostic information about the state of the cache 74 */ 75 static void Dump(); 76 77 /////////////////////////////////////////////////////////////////////////// 78 79 /** 80 * Construct the cache to call DiscardableFactory when it 81 * allocates memory for the pixels. In this mode, the cache has 82 * not explicit budget, and so methods like getTotalBytesUsed() 83 * and getTotalByteLimit() will return 0, and setTotalByteLimit 84 * will ignore its argument and return 0. 85 */ 86 SkScaledImageCache(DiscardableFactory); 87 88 /** 89 * Construct the cache, allocating memory with malloc, and respect the 90 * byteLimit, purging automatically when a new image is added to the cache 91 * that pushes the total bytesUsed over the limit. Note: The limit can be 92 * changed at runtime with setTotalByteLimit. 93 */ 94 SkScaledImageCache(size_t byteLimit); 95 96 ~SkScaledImageCache(); 97 98 /** 99 * Search the cache for a matching bitmap (using generationID, 100 * width, and height as a search key). If found, return it in 101 * returnedBitmap, and return its ID pointer. Use the returned 102 * ptr to unlock the cache when you are done using 103 * returnedBitmap. 104 * 105 * If a match is not found, returnedBitmap will be unmodifed, and 106 * NULL will be returned. 107 * 108 * This is used if there is no scaling or subsetting, for example 109 * by SkLazyPixelRef. 110 */ 111 ID* findAndLock(uint32_t pixelGenerationID, int32_t width, int32_t height, 112 SkBitmap* returnedBitmap); 113 114 /** 115 * Search the cache for a scaled version of original. If found, 116 * return it in returnedBitmap, and return its ID pointer. Use 117 * the returned ptr to unlock the cache when you are done using 118 * returnedBitmap. 119 * 120 * If a match is not found, returnedBitmap will be unmodifed, and 121 * NULL will be returned. 122 */ 123 ID* findAndLock(const SkBitmap& original, SkScalar scaleX, 124 SkScalar scaleY, SkBitmap* returnedBitmap); 125 ID* findAndLockMip(const SkBitmap& original, 126 SkMipMap const** returnedMipMap); 127 128 /** 129 * To add a new bitmap (or mipMap) to the cache, call 130 * AddAndLock. Use the returned ptr to unlock the cache when you 131 * are done using scaled. 132 * 133 * Use (generationID, width, and height) or (original, scaleX, 134 * scaleY) or (original) as a search key 135 */ 136 ID* addAndLock(uint32_t pixelGenerationID, int32_t width, int32_t height, 137 const SkBitmap& bitmap); 138 ID* addAndLock(const SkBitmap& original, SkScalar scaleX, 139 SkScalar scaleY, const SkBitmap& bitmap); 140 ID* addAndLockMip(const SkBitmap& original, const SkMipMap* mipMap); 141 142 /** 143 * Given a non-null ID ptr returned by either findAndLock or addAndLock, 144 * this releases the associated resources to be available to be purged 145 * if needed. After this, the cached bitmap should no longer be 146 * referenced by the caller. 147 */ 148 void unlock(ID*); 149 getTotalBytesUsed()150 size_t getTotalBytesUsed() const { return fTotalBytesUsed; } getTotalByteLimit()151 size_t getTotalByteLimit() const { return fTotalByteLimit; } 152 153 /** 154 * This is respected by SkBitmapProcState::possiblyScaleImage. 155 * 0 is no maximum at all; this is the default. 156 * setSingleAllocationByteLimit() returns the previous value. 157 */ 158 size_t setSingleAllocationByteLimit(size_t maximumAllocationSize); 159 size_t getSingleAllocationByteLimit() const; 160 /** 161 * Set the maximum number of bytes available to this cache. If the current 162 * cache exceeds this new value, it will be purged to try to fit within 163 * this new limit. 164 */ 165 size_t setTotalByteLimit(size_t newLimit); 166 allocator()167 SkBitmap::Allocator* allocator() const { return fAllocator; }; 168 169 /** 170 * Call SkDebugf() with diagnostic information about the state of the cache 171 */ 172 void dump() const; 173 174 public: 175 struct Rec; 176 struct Key; 177 private: 178 Rec* fHead; 179 Rec* fTail; 180 181 class Hash; 182 Hash* fHash; 183 184 DiscardableFactory fDiscardableFactory; 185 // the allocator is NULL or one that matches discardables 186 SkBitmap::Allocator* fAllocator; 187 188 size_t fTotalBytesUsed; 189 size_t fTotalByteLimit; 190 size_t fSingleAllocationByteLimit; 191 int fCount; 192 193 Rec* findAndLock(uint32_t generationID, SkScalar sx, SkScalar sy, 194 const SkIRect& bounds); 195 Rec* findAndLock(const Key& key); 196 ID* addAndLock(Rec* rec); 197 198 void purgeRec(Rec*); 199 void purgeAsNeeded(); 200 201 // linklist management 202 void moveToHead(Rec*); 203 void addToHead(Rec*); 204 void detach(Rec*); 205 206 void init(); // called by constructors 207 208 #ifdef SK_DEBUG 209 void validate() const; 210 #else validate()211 void validate() const {} 212 #endif 213 }; 214 #endif 215