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 SkASSERT(image->width() > 0 && image->height() > 0); 54 return SkIRect::MakeWH(image->width(), image->height()); 55 } 56 57 SkBitmapCacheDesc SkBitmapCacheDesc::Make(uint32_t imageID, int origWidth, int origHeight) { 58 SkASSERT(imageID); 59 SkASSERT(origWidth > 0 && origHeight > 0); 60 return { imageID, 0, 0, {0, 0, origWidth, origHeight} }; 61 } 62 63 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm, int scaledWidth, int scaledHeight) { 64 SkASSERT(bm.width() > 0 && bm.height() > 0); 65 SkASSERT(scaledWidth > 0 && scaledHeight > 0); 66 SkASSERT(scaledWidth != bm.width() || scaledHeight != bm.height()); 67 68 return { bm.getGenerationID(), scaledWidth, scaledHeight, get_bounds_from_bitmap(bm) }; 69 } 70 71 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) { 72 SkASSERT(bm.width() > 0 && bm.height() > 0); 73 SkASSERT(bm.pixelRefOrigin() == SkIPoint::Make(0, 0)); 74 75 return { bm.getGenerationID(), 0, 0, get_bounds_from_bitmap(bm) }; 76 } 77 78 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image, int scaledWidth, int scaledHeight) { 79 SkASSERT(image->width() > 0 && image->height() > 0); 80 SkASSERT(scaledWidth > 0 && scaledHeight > 0); 81 82 // If the dimensions are the same, should we set them to 0,0? 83 //SkASSERT(scaledWidth != image->width() || scaledHeight != image->height()); 84 85 return { image->uniqueID(), scaledWidth, scaledHeight, get_bounds_from_image(image) }; 86 } 87 88 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) { 89 SkASSERT(image->width() > 0 && image->height() > 0); 90 91 return { image->uniqueID(), 0, 0, get_bounds_from_image(image) }; 92 } 93 94 namespace { 95 static unsigned gBitmapKeyNamespaceLabel; 96 97 struct BitmapKey : public SkResourceCache::Key { 98 public: 99 BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) { 100 this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID), 101 sizeof(fDesc)); 102 } 103 104 void dump() const { 105 SkDebugf("-- add [%d %d] %d [%d %d %d %d]\n", 106 fDesc.fScaledWidth, fDesc.fScaledHeight, fDesc.fImageID, 107 fDesc.fSubset.x(), fDesc.fSubset.y(), fDesc.fSubset.width(), fDesc.fSubset.height()); 108 } 109 110 const SkBitmapCacheDesc fDesc; 111 }; 112 113 struct BitmapRec : public SkResourceCache::Rec { 114 BitmapRec(const SkBitmapCacheDesc& desc, const SkBitmap& result) 115 : fKey(desc) 116 , fBitmap(result) 117 { 118 #ifdef TRACE_NEW_BITMAP_CACHE_RECS 119 fKey.dump(); 120 #endif 121 } 122 123 const Key& getKey() const override { return fKey; } 124 size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); } 125 126 const char* getCategory() const override { return "bitmap"; } 127 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { 128 return fBitmap.pixelRef()->diagnostic_only_getDiscardable(); 129 } 130 131 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) { 132 const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec); 133 SkBitmap* result = (SkBitmap*)contextBitmap; 134 135 *result = rec.fBitmap; 136 result->lockPixels(); 137 return SkToBool(result->getPixels()); 138 } 139 140 private: 141 BitmapKey fKey; 142 SkBitmap fBitmap; 143 }; 144 } // namespace 145 146 #define CHECK_LOCAL(localCache, localName, globalName, ...) \ 147 ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__)) 148 149 bool SkBitmapCache::Find(const SkBitmapCacheDesc& desc, SkBitmap* result, 150 SkResourceCache* localCache) { 151 desc.validate(); 152 return CHECK_LOCAL(localCache, find, Find, BitmapKey(desc), BitmapRec::Finder, result); 153 } 154 155 bool SkBitmapCache::Add(const SkBitmapCacheDesc& desc, const SkBitmap& result, 156 SkResourceCache* localCache) { 157 desc.validate(); 158 SkASSERT(result.isImmutable()); 159 BitmapRec* rec = new BitmapRec(desc, result); 160 CHECK_LOCAL(localCache, add, Add, rec); 161 return true; 162 } 163 164 ////////////////////////////////////////////////////////////////////////////////////////// 165 ////////////////////////////////////////////////////////////////////////////////////////// 166 167 namespace { 168 static unsigned gMipMapKeyNamespaceLabel; 169 170 struct MipMapKey : public SkResourceCache::Key { 171 public: 172 MipMapKey(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode) 173 : fImageID(imageID) 174 , fColorMode(static_cast<uint32_t>(colorMode)) 175 , fSubset(subset) 176 { 177 SkASSERT(fImageID); 178 SkASSERT(!subset.isEmpty()); 179 this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fImageID), 180 sizeof(fImageID) + sizeof(fColorMode) + sizeof(fSubset)); 181 } 182 183 uint32_t fImageID; 184 uint32_t fColorMode; 185 SkIRect fSubset; 186 }; 187 188 struct MipMapRec : public SkResourceCache::Rec { 189 MipMapRec(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode, 190 const SkMipMap* result) 191 : fKey(imageID, subset, colorMode) 192 , fMipMap(result) 193 { 194 fMipMap->attachToCacheAndRef(); 195 } 196 197 ~MipMapRec() override { 198 fMipMap->detachFromCacheAndUnref(); 199 } 200 201 const Key& getKey() const override { return fKey; } 202 size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); } 203 const char* getCategory() const override { return "mipmap"; } 204 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { 205 return fMipMap->diagnostic_only_getDiscardable(); 206 } 207 208 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) { 209 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec); 210 const SkMipMap* mm = SkRef(rec.fMipMap); 211 // the call to ref() above triggers a "lock" in the case of discardable memory, 212 // which means we can now check for null (in case the lock failed). 213 if (nullptr == mm->data()) { 214 mm->unref(); // balance our call to ref() 215 return false; 216 } 217 // the call must call unref() when they are done. 218 *(const SkMipMap**)contextMip = mm; 219 return true; 220 } 221 222 private: 223 MipMapKey fKey; 224 const SkMipMap* fMipMap; 225 }; 226 } 227 228 const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc, 229 SkDestinationSurfaceColorMode colorMode, 230 SkResourceCache* localCache) { 231 SkASSERT(desc.fScaledWidth == 0); 232 SkASSERT(desc.fScaledHeight == 0); 233 MipMapKey key(desc.fImageID, desc.fSubset, colorMode); 234 const SkMipMap* result; 235 236 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) { 237 result = nullptr; 238 } 239 return result; 240 } 241 242 static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) { 243 return localCache ? localCache->GetDiscardableFactory() 244 : SkResourceCache::GetDiscardableFactory(); 245 } 246 247 const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, 248 SkDestinationSurfaceColorMode colorMode, 249 SkResourceCache* localCache) { 250 SkMipMap* mipmap = SkMipMap::Build(src, colorMode, get_fact(localCache)); 251 if (mipmap) { 252 MipMapRec* rec = new MipMapRec(src.getGenerationID(), get_bounds_from_bitmap(src), 253 colorMode, mipmap); 254 CHECK_LOCAL(localCache, add, Add, rec); 255 src.pixelRef()->notifyAddedToCache(); 256 } 257 return mipmap; 258 } 259