1 /* 2 * Copyright 2014 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 #include "SkBitmapCache.h" 9 #include "SkImage.h" 10 #include "SkResourceCache.h" 11 #include "SkMipMap.h" 12 #include "SkPixelRef.h" 13 #include "SkRect.h" 14 15 /** 16 * Use this for bitmapcache and mipmapcache entries. 17 */ 18 uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) { 19 uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p'); 20 return (sharedID << 32) | bitmapGenID; 21 } 22 23 void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) { 24 SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID)); 25 } 26 27 /////////////////////////////////////////////////////////////////////////////////////////////////// 28 29 SkBitmap::Allocator* SkBitmapCache::GetAllocator() { 30 return SkResourceCache::GetAllocator(); 31 } 32 33 /** 34 This function finds the bounds of the bitmap *within its pixelRef*. 35 If the bitmap lacks a pixelRef, it will return an empty rect, since 36 that doesn't make sense. This may be a useful enough function that 37 it should be somewhere else (in SkBitmap?). 38 */ 39 static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) { 40 if (!(bm.pixelRef())) { 41 return SkIRect::MakeEmpty(); 42 } 43 SkIPoint origin = bm.pixelRefOrigin(); 44 return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height()); 45 } 46 47 /** 48 * This function finds the bounds of the image. Today this is just the entire bounds, 49 * but in the future we may support subsets within an image, in which case this should 50 * return that subset (see get_bounds_from_bitmap). 51 */ 52 static SkIRect get_bounds_from_image(const SkImage* image) { 53 return SkIRect::MakeWH(image->width(), image->height()); 54 } 55 56 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm, int width, int height) { 57 SkBitmapCacheDesc desc; 58 desc.fImageID = bm.getGenerationID(); 59 desc.fWidth = width; 60 desc.fHeight = height; 61 desc.fBounds = get_bounds_from_bitmap(bm); 62 return desc; 63 } 64 65 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) { 66 return Make(bm, bm.width(), bm.height()); 67 } 68 69 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image, int width, int height) { 70 SkBitmapCacheDesc desc; 71 desc.fImageID = image->uniqueID(); 72 desc.fWidth = width; 73 desc.fHeight = height; 74 desc.fBounds = get_bounds_from_image(image); 75 return desc; 76 } 77 78 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) { 79 return Make(image, image->width(), image->height()); 80 } 81 82 namespace { 83 static unsigned gBitmapKeyNamespaceLabel; 84 85 struct BitmapKey : public SkResourceCache::Key { 86 public: 87 BitmapKey(uint32_t genID, int width, int height, const SkIRect& bounds) 88 : fGenID(genID) 89 , fWidth(width) 90 , fHeight(height) 91 , fBounds(bounds) 92 { 93 this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fGenID), 94 sizeof(fGenID) + sizeof(fWidth) + sizeof(fHeight) + sizeof(fBounds)); 95 } 96 97 BitmapKey(const SkBitmapCacheDesc& desc) 98 : fGenID(desc.fImageID) 99 , fWidth(desc.fWidth) 100 , fHeight(desc.fHeight) 101 , fBounds(desc.fBounds) 102 { 103 this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fGenID), 104 sizeof(fGenID) + sizeof(fWidth) + sizeof(fHeight) + sizeof(fBounds)); 105 } 106 107 void dump() const { 108 SkDebugf("-- add [%d %d] %d [%d %d %d %d]\n", fWidth, fHeight, fGenID, 109 fBounds.x(), fBounds.y(), fBounds.width(), fBounds.height()); 110 } 111 112 const uint32_t fGenID; 113 const int fWidth; 114 const int fHeight; 115 const SkIRect fBounds; 116 }; 117 118 struct BitmapRec : public SkResourceCache::Rec { 119 BitmapRec(uint32_t genID, int width, int height, const SkIRect& bounds, 120 const SkBitmap& result) 121 : fKey(genID, width, height, bounds) 122 , fBitmap(result) 123 { 124 #ifdef TRACE_NEW_BITMAP_CACHE_RECS 125 fKey.dump(); 126 #endif 127 } 128 129 BitmapRec(const SkBitmapCacheDesc& desc, const SkBitmap& result) 130 : fKey(desc) 131 , fBitmap(result) 132 { 133 #ifdef TRACE_NEW_BITMAP_CACHE_RECS 134 fKey.dump(); 135 #endif 136 } 137 138 const Key& getKey() const override { return fKey; } 139 size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); } 140 141 const char* getCategory() const override { return "bitmap"; } 142 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { 143 return fBitmap.pixelRef()->diagnostic_only_getDiscardable(); 144 } 145 146 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) { 147 const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec); 148 SkBitmap* result = (SkBitmap*)contextBitmap; 149 150 *result = rec.fBitmap; 151 result->lockPixels(); 152 return SkToBool(result->getPixels()); 153 } 154 155 private: 156 BitmapKey fKey; 157 SkBitmap fBitmap; 158 }; 159 } // namespace 160 161 #define CHECK_LOCAL(localCache, localName, globalName, ...) \ 162 ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__)) 163 164 bool SkBitmapCache::FindWH(const SkBitmapCacheDesc& desc, SkBitmap* result, 165 SkResourceCache* localCache) { 166 if (0 == desc.fWidth || 0 == desc.fHeight) { 167 // degenerate 168 return false; 169 } 170 return CHECK_LOCAL(localCache, find, Find, BitmapKey(desc), BitmapRec::Finder, result); 171 } 172 173 bool SkBitmapCache::AddWH(const SkBitmapCacheDesc& desc, const SkBitmap& result, 174 SkResourceCache* localCache) { 175 if (0 == desc.fWidth || 0 == desc.fHeight) { 176 // degenerate, and the key we use for mipmaps 177 return false; 178 } 179 SkASSERT(result.isImmutable()); 180 BitmapRec* rec = new BitmapRec(desc, result); 181 CHECK_LOCAL(localCache, add, Add, rec); 182 return true; 183 } 184 185 bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result, 186 SkResourceCache* localCache) { 187 BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset); 188 189 return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result); 190 } 191 192 bool SkBitmapCache::Add(SkPixelRef* pr, const SkIRect& subset, const SkBitmap& result, 193 SkResourceCache* localCache) { 194 SkASSERT(result.isImmutable()); 195 196 if (subset.isEmpty() 197 || subset.top() < 0 198 || subset.left() < 0 199 || result.width() != subset.width() 200 || result.height() != subset.height()) { 201 return false; 202 } else { 203 BitmapRec* rec = new BitmapRec(pr->getGenerationID(), 1, 1, subset, result); 204 205 CHECK_LOCAL(localCache, add, Add, rec); 206 pr->notifyAddedToCache(); 207 return true; 208 } 209 } 210 211 bool SkBitmapCache::Find(uint32_t genID, SkBitmap* result, SkResourceCache* localCache) { 212 BitmapKey key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeEmpty()); 213 214 return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result); 215 } 216 217 void SkBitmapCache::Add(uint32_t genID, const SkBitmap& result, SkResourceCache* localCache) { 218 SkASSERT(result.isImmutable()); 219 220 BitmapRec* rec = new BitmapRec(genID, 1, 1, SkIRect::MakeEmpty(), result); 221 222 CHECK_LOCAL(localCache, add, Add, rec); 223 } 224 225 ////////////////////////////////////////////////////////////////////////////////////////// 226 ////////////////////////////////////////////////////////////////////////////////////////// 227 228 namespace { 229 static unsigned gMipMapKeyNamespaceLabel; 230 231 struct MipMapKey : public SkResourceCache::Key { 232 public: 233 MipMapKey(uint32_t genID, const SkIRect& bounds) : fGenID(genID), fBounds(bounds) { 234 this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID), 235 sizeof(fGenID) + sizeof(fBounds)); 236 } 237 238 uint32_t fGenID; 239 SkIRect fBounds; 240 }; 241 242 struct MipMapRec : public SkResourceCache::Rec { 243 MipMapRec(const SkBitmap& src, const SkMipMap* result) 244 : fKey(src.getGenerationID(), get_bounds_from_bitmap(src)) 245 , fMipMap(result) 246 { 247 fMipMap->attachToCacheAndRef(); 248 } 249 250 virtual ~MipMapRec() { 251 fMipMap->detachFromCacheAndUnref(); 252 } 253 254 const Key& getKey() const override { return fKey; } 255 size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); } 256 const char* getCategory() const override { return "mipmap"; } 257 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { 258 return fMipMap->diagnostic_only_getDiscardable(); 259 } 260 261 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) { 262 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec); 263 const SkMipMap* mm = SkRef(rec.fMipMap); 264 // the call to ref() above triggers a "lock" in the case of discardable memory, 265 // which means we can now check for null (in case the lock failed). 266 if (nullptr == mm->data()) { 267 mm->unref(); // balance our call to ref() 268 return false; 269 } 270 // the call must call unref() when they are done. 271 *(const SkMipMap**)contextMip = mm; 272 return true; 273 } 274 275 private: 276 MipMapKey fKey; 277 const SkMipMap* fMipMap; 278 }; 279 } 280 281 const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc, 282 SkResourceCache* localCache) { 283 // Note: we ignore width/height from desc, just need id and bounds 284 MipMapKey key(desc.fImageID, desc.fBounds); 285 const SkMipMap* result; 286 287 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) { 288 result = nullptr; 289 } 290 return result; 291 } 292 293 static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) { 294 return localCache ? localCache->GetDiscardableFactory() 295 : SkResourceCache::GetDiscardableFactory(); 296 } 297 298 const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkResourceCache* localCache) { 299 SkMipMap* mipmap = SkMipMap::Build(src, get_fact(localCache)); 300 if (mipmap) { 301 MipMapRec* rec = new MipMapRec(src, mipmap); 302 CHECK_LOCAL(localCache, add, Add, rec); 303 src.pixelRef()->notifyAddedToCache(); 304 } 305 return mipmap; 306 } 307