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