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     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