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 "SkResourceCache.h" 10 #include "SkMipMap.h" 11 #include "SkPixelRef.h" 12 #include "SkRect.h" 13 14 /** 15 * Use this for bitmapcache and mipmapcache entries. 16 */ 17 uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) { 18 uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p'); 19 return (sharedID << 32) | bitmapGenID; 20 } 21 22 void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) { 23 SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID)); 24 } 25 26 /////////////////////////////////////////////////////////////////////////////////////////////////// 27 28 SkBitmap::Allocator* SkBitmapCache::GetAllocator() { 29 return SkResourceCache::GetAllocator(); 30 } 31 32 /** 33 This function finds the bounds of the bitmap *within its pixelRef*. 34 If the bitmap lacks a pixelRef, it will return an empty rect, since 35 that doesn't make sense. This may be a useful enough function that 36 it should be somewhere else (in SkBitmap?). 37 */ 38 static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) { 39 if (!(bm.pixelRef())) { 40 return SkIRect::MakeEmpty(); 41 } 42 SkIPoint origin = bm.pixelRefOrigin(); 43 return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height()); 44 } 45 46 namespace { 47 static unsigned gBitmapKeyNamespaceLabel; 48 49 struct BitmapKey : public SkResourceCache::Key { 50 public: 51 BitmapKey(uint32_t genID, SkScalar sx, SkScalar sy, const SkIRect& bounds) 52 : fGenID(genID) 53 , fScaleX(sx) 54 , fScaleY(sy) 55 , fBounds(bounds) 56 { 57 this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID), 58 sizeof(fGenID) + sizeof(fScaleX) + sizeof(fScaleY) + sizeof(fBounds)); 59 } 60 61 uint32_t fGenID; 62 SkScalar fScaleX; 63 SkScalar fScaleY; 64 SkIRect fBounds; 65 }; 66 67 struct BitmapRec : public SkResourceCache::Rec { 68 BitmapRec(uint32_t genID, SkScalar scaleX, SkScalar scaleY, const SkIRect& bounds, 69 const SkBitmap& result) 70 : fKey(genID, scaleX, scaleY, bounds) 71 , fBitmap(result) 72 {} 73 74 const Key& getKey() const override { return fKey; } 75 size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); } 76 77 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) { 78 const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec); 79 SkBitmap* result = (SkBitmap*)contextBitmap; 80 81 *result = rec.fBitmap; 82 result->lockPixels(); 83 return SkToBool(result->getPixels()); 84 } 85 86 private: 87 BitmapKey fKey; 88 SkBitmap fBitmap; 89 }; 90 } // namespace 91 92 #define CHECK_LOCAL(localCache, localName, globalName, ...) \ 93 ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__)) 94 95 bool SkBitmapCache::Find(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY, SkBitmap* result, 96 SkResourceCache* localCache) { 97 if (0 == invScaleX || 0 == invScaleY) { 98 // degenerate, and the key we use for mipmaps 99 return false; 100 } 101 BitmapKey key(src.getGenerationID(), invScaleX, invScaleY, get_bounds_from_bitmap(src)); 102 103 return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result); 104 } 105 106 void SkBitmapCache::Add(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY, 107 const SkBitmap& result, SkResourceCache* localCache) { 108 if (0 == invScaleX || 0 == invScaleY) { 109 // degenerate, and the key we use for mipmaps 110 return; 111 } 112 SkASSERT(result.isImmutable()); 113 BitmapRec* rec = SkNEW_ARGS(BitmapRec, (src.getGenerationID(), invScaleX, invScaleY, 114 get_bounds_from_bitmap(src), result)); 115 CHECK_LOCAL(localCache, add, Add, rec); 116 src.pixelRef()->notifyAddedToCache(); 117 } 118 119 bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result, 120 SkResourceCache* localCache) { 121 BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset); 122 123 return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result); 124 } 125 126 bool SkBitmapCache::Add(SkPixelRef* pr, const SkIRect& subset, const SkBitmap& result, 127 SkResourceCache* localCache) { 128 SkASSERT(result.isImmutable()); 129 130 if (subset.isEmpty() 131 || subset.top() < 0 132 || subset.left() < 0 133 || result.width() != subset.width() 134 || result.height() != subset.height()) { 135 return false; 136 } else { 137 BitmapRec* rec = SkNEW_ARGS(BitmapRec, (pr->getGenerationID(), 1, 1, subset, result)); 138 139 CHECK_LOCAL(localCache, add, Add, rec); 140 pr->notifyAddedToCache(); 141 return true; 142 } 143 } 144 145 ////////////////////////////////////////////////////////////////////////////////////////// 146 ////////////////////////////////////////////////////////////////////////////////////////// 147 148 namespace { 149 static unsigned gMipMapKeyNamespaceLabel; 150 151 struct MipMapKey : public SkResourceCache::Key { 152 public: 153 MipMapKey(uint32_t genID, const SkIRect& bounds) : fGenID(genID), fBounds(bounds) { 154 this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID), 155 sizeof(fGenID) + sizeof(fBounds)); 156 } 157 158 uint32_t fGenID; 159 SkIRect fBounds; 160 }; 161 162 struct MipMapRec : public SkResourceCache::Rec { 163 MipMapRec(const SkBitmap& src, const SkMipMap* result) 164 : fKey(src.getGenerationID(), get_bounds_from_bitmap(src)) 165 , fMipMap(result) 166 { 167 fMipMap->attachToCacheAndRef(); 168 } 169 170 virtual ~MipMapRec() { 171 fMipMap->detachFromCacheAndUnref(); 172 } 173 174 const Key& getKey() const override { return fKey; } 175 size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); } 176 177 static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) { 178 const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec); 179 const SkMipMap* mm = SkRef(rec.fMipMap); 180 // the call to ref() above triggers a "lock" in the case of discardable memory, 181 // which means we can now check for null (in case the lock failed). 182 if (NULL == mm->data()) { 183 mm->unref(); // balance our call to ref() 184 return false; 185 } 186 // the call must call unref() when they are done. 187 *(const SkMipMap**)contextMip = mm; 188 return true; 189 } 190 191 private: 192 MipMapKey fKey; 193 const SkMipMap* fMipMap; 194 }; 195 } 196 197 const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmap& src, SkResourceCache* localCache) { 198 MipMapKey key(src.getGenerationID(), get_bounds_from_bitmap(src)); 199 const SkMipMap* result; 200 201 if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) { 202 result = NULL; 203 } 204 return result; 205 } 206 207 static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) { 208 return localCache ? localCache->GetDiscardableFactory() 209 : SkResourceCache::GetDiscardableFactory(); 210 } 211 212 const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkResourceCache* localCache) { 213 SkMipMap* mipmap = SkMipMap::Build(src, get_fact(localCache)); 214 if (mipmap) { 215 MipMapRec* rec = SkNEW_ARGS(MipMapRec, (src, mipmap)); 216 CHECK_LOCAL(localCache, add, Add, rec); 217 src.pixelRef()->notifyAddedToCache(); 218 } 219 return mipmap; 220 } 221