SkBitmapCache.cpp revision 6644d9353f3f0c09914385fd762e073f98d54205
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 */ 18uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) { 19 uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p'); 20 return (sharedID << 32) | bitmapGenID; 21} 22 23void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) { 24 SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID)); 25} 26 27/////////////////////////////////////////////////////////////////////////////////////////////////// 28 29SkBitmap::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 */ 39static 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 */ 52static SkIRect get_bounds_from_image(const SkImage* image) { 53 return SkIRect::MakeWH(image->width(), image->height()); 54} 55 56SkBitmapCacheDesc 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 65SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) { 66 return Make(bm, bm.width(), bm.height()); 67} 68 69SkBitmapCacheDesc 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 78SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) { 79 return Make(image, image->width(), image->height()); 80} 81 82namespace { 83static unsigned gBitmapKeyNamespaceLabel; 84 85struct BitmapKey : public SkResourceCache::Key { 86public: 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 118struct 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 155private: 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 164bool 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 173bool 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 185bool 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 192bool 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 211bool 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 217void 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 228namespace { 229static unsigned gMipMapKeyNamespaceLabel; 230 231struct MipMapKey : public SkResourceCache::Key { 232public: 233 MipMapKey(uint32_t genID, SkSourceGammaTreatment treatment, const SkIRect& bounds) 234 : fGenID(genID), fSrcGammaTreatment(static_cast<uint32_t>(treatment)), fBounds(bounds) 235 { 236 this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID), 237 sizeof(fGenID) + sizeof(fSrcGammaTreatment) + sizeof(fBounds)); 238 } 239 240 uint32_t fGenID; 241 uint32_t fSrcGammaTreatment; 242 SkIRect fBounds; 243}; 244 245struct MipMapRec : public SkResourceCache::Rec { 246 MipMapRec(const SkBitmap& src, SkSourceGammaTreatment treatment, const SkMipMap* result) 247 : fKey(src.getGenerationID(), treatment, get_bounds_from_bitmap(src)) 248 , fMipMap(result) 249 { 250 fMipMap->attachToCacheAndRef(); 251 } 252 253 virtual ~MipMapRec() { 254 fMipMap->detachFromCacheAndUnref(); 255 } 256 257 const Key& getKey() const override { return fKey; } 258 size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); } 259 const char* getCategory() const override { return "mipmap"; } 260 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { 261 return fMipMap->diagnostic_only_getDiscardable(); 262 } 263 264 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) { 265 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec); 266 const SkMipMap* mm = SkRef(rec.fMipMap); 267 // the call to ref() above triggers a "lock" in the case of discardable memory, 268 // which means we can now check for null (in case the lock failed). 269 if (nullptr == mm->data()) { 270 mm->unref(); // balance our call to ref() 271 return false; 272 } 273 // the call must call unref() when they are done. 274 *(const SkMipMap**)contextMip = mm; 275 return true; 276 } 277 278private: 279 MipMapKey fKey; 280 const SkMipMap* fMipMap; 281}; 282} 283 284const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc, 285 SkSourceGammaTreatment treatment, 286 SkResourceCache* localCache) { 287 // Note: we ignore width/height from desc, just need id and bounds 288 MipMapKey key(desc.fImageID, treatment, desc.fBounds); 289 const SkMipMap* result; 290 291 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) { 292 result = nullptr; 293 } 294 return result; 295} 296 297static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) { 298 return localCache ? localCache->GetDiscardableFactory() 299 : SkResourceCache::GetDiscardableFactory(); 300} 301 302const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkSourceGammaTreatment treatment, 303 SkResourceCache* localCache) { 304 SkMipMap* mipmap = SkMipMap::Build(src, treatment, get_fact(localCache)); 305 if (mipmap) { 306 MipMapRec* rec = new MipMapRec(src, treatment, mipmap); 307 CHECK_LOCAL(localCache, add, Add, rec); 308 src.pixelRef()->notifyAddedToCache(); 309 } 310 return mipmap; 311} 312