Home | History | Annotate | Download | only in core
      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