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 /**
     30  This function finds the bounds of the bitmap *within its pixelRef*.
     31  If the bitmap lacks a pixelRef, it will return an empty rect, since
     32  that doesn't make sense.  This may be a useful enough function that
     33  it should be somewhere else (in SkBitmap?).
     34  */
     35 static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) {
     36     if (!(bm.pixelRef())) {
     37         return SkIRect::MakeEmpty();
     38     }
     39     SkIPoint origin = bm.pixelRefOrigin();
     40     return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height());
     41 }
     42 
     43 /**
     44  *  This function finds the bounds of the image. Today this is just the entire bounds,
     45  *  but in the future we may support subsets within an image, in which case this should
     46  *  return that subset (see get_bounds_from_bitmap).
     47  */
     48 static SkIRect get_bounds_from_image(const SkImage* image) {
     49     SkASSERT(image->width() > 0 && image->height() > 0);
     50     return SkIRect::MakeWH(image->width(), image->height());
     51 }
     52 
     53 SkBitmapCacheDesc SkBitmapCacheDesc::Make(uint32_t imageID, int origWidth, int origHeight) {
     54     SkASSERT(imageID);
     55     SkASSERT(origWidth > 0 && origHeight > 0);
     56     return { imageID, 0, 0, {0, 0, origWidth, origHeight} };
     57 }
     58 
     59 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm, int scaledWidth, int scaledHeight) {
     60     SkASSERT(bm.width() > 0 && bm.height() > 0);
     61     SkASSERT(scaledWidth > 0 && scaledHeight > 0);
     62     SkASSERT(scaledWidth != bm.width() || scaledHeight != bm.height());
     63 
     64     return { bm.getGenerationID(), scaledWidth, scaledHeight, get_bounds_from_bitmap(bm) };
     65 }
     66 
     67 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkBitmap& bm) {
     68     SkASSERT(bm.width() > 0 && bm.height() > 0);
     69     SkASSERT(bm.pixelRefOrigin() == SkIPoint::Make(0, 0));
     70 
     71     return { bm.getGenerationID(), 0, 0, get_bounds_from_bitmap(bm) };
     72 }
     73 
     74 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image, int scaledWidth, int scaledHeight) {
     75     SkASSERT(image->width() > 0 && image->height() > 0);
     76     SkASSERT(scaledWidth > 0 && scaledHeight > 0);
     77 
     78     // If the dimensions are the same, should we set them to 0,0?
     79     //SkASSERT(scaledWidth != image->width() || scaledHeight != image->height());
     80 
     81     return { image->uniqueID(), scaledWidth, scaledHeight, get_bounds_from_image(image) };
     82 }
     83 
     84 SkBitmapCacheDesc SkBitmapCacheDesc::Make(const SkImage* image) {
     85     SkASSERT(image->width() > 0 && image->height() > 0);
     86 
     87     return { image->uniqueID(), 0, 0, get_bounds_from_image(image) };
     88 }
     89 
     90 namespace {
     91 static unsigned gBitmapKeyNamespaceLabel;
     92 
     93 struct BitmapKey : public SkResourceCache::Key {
     94 public:
     95     BitmapKey(const SkBitmapCacheDesc& desc) : fDesc(desc) {
     96         this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fDesc.fImageID),
     97                    sizeof(fDesc));
     98     }
     99 
    100     void dump() const {
    101         SkDebugf("-- add [%d %d] %d [%d %d %d %d]\n",
    102                  fDesc.fScaledWidth, fDesc.fScaledHeight, fDesc.fImageID,
    103              fDesc.fSubset.x(), fDesc.fSubset.y(), fDesc.fSubset.width(), fDesc.fSubset.height());
    104     }
    105 
    106     const SkBitmapCacheDesc fDesc;
    107 };
    108 }
    109 
    110 //////////////////////
    111 #include "SkDiscardableMemory.h"
    112 #include "SkNextID.h"
    113 
    114 void SkBitmapCache_setImmutableWithID(SkPixelRef* pr, uint32_t id) {
    115     pr->setImmutableWithID(id);
    116 }
    117 
    118 //#define REC_TRACE   SkDebugf
    119 static void REC_TRACE(const char format[], ...) {}
    120 
    121 // for diagnostics
    122 static int32_t gRecCounter;
    123 
    124 class SkBitmapCache::Rec : public SkResourceCache::Rec {
    125 public:
    126     Rec(const SkBitmapCacheDesc& desc, const SkImageInfo& info, size_t rowBytes,
    127         std::unique_ptr<SkDiscardableMemory> dm, void* block)
    128         : fKey(desc)
    129         , fDM(std::move(dm))
    130         , fMalloc(block)
    131         , fInfo(info)
    132         , fRowBytes(rowBytes)
    133         , fExternalCounter(kBeforeFirstInstall_ExternalCounter)
    134     {
    135         SkASSERT(!(fDM && fMalloc));    // can't have both
    136 
    137         // We need an ID to return with the bitmap/pixelref.
    138         // If they are not scaling, we can return the same ID as the key/desc
    139         // If they are scaling, we need a new ID
    140         if (desc.fScaledWidth == 0 && desc.fScaledHeight == 0) {
    141             fPrUniqueID = desc.fImageID;
    142         } else {
    143             fPrUniqueID = SkNextID::ImageID();
    144         }
    145         REC_TRACE(" Rec(%d): [%d %d] %d\n",
    146                   sk_atomic_inc(&gRecCounter), fInfo.width(), fInfo.height(), fPrUniqueID);
    147     }
    148 
    149     ~Rec() override {
    150         SkASSERT(0 == fExternalCounter || kBeforeFirstInstall_ExternalCounter == fExternalCounter);
    151         if (fDM && kBeforeFirstInstall_ExternalCounter == fExternalCounter) {
    152             // we never installed, so we need to unlock before we destroy the DM
    153             SkASSERT(fDM->data());
    154             fDM->unlock();
    155         }
    156         REC_TRACE("~Rec(%d): [%d %d] %d\n",
    157                   sk_atomic_dec(&gRecCounter) - 1, fInfo.width(), fInfo.height(), fPrUniqueID);
    158         sk_free(fMalloc);   // may be null
    159     }
    160 
    161     const Key& getKey() const override { return fKey; }
    162     size_t bytesUsed() const override {
    163         return sizeof(fKey) + fInfo.computeByteSize(fRowBytes);
    164     }
    165     bool canBePurged() override {
    166         SkAutoMutexAcquire ama(fMutex);
    167         return fExternalCounter == 0;
    168     }
    169     void postAddInstall(void* payload) override {
    170         SkAssertResult(this->install(static_cast<SkBitmap*>(payload)));
    171     }
    172 
    173     const char* getCategory() const override { return "bitmap"; }
    174     SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
    175         return fDM.get();
    176     }
    177 
    178     static void ReleaseProc(void* addr, void* ctx) {
    179         Rec* rec = static_cast<Rec*>(ctx);
    180         SkAutoMutexAcquire ama(rec->fMutex);
    181 
    182         REC_TRACE(" Rec: [%d] releaseproc\n", rec->fPrUniqueID);
    183 
    184         SkASSERT(rec->fExternalCounter > 0);
    185         rec->fExternalCounter -= 1;
    186         if (rec->fDM) {
    187             SkASSERT(rec->fMalloc == nullptr);
    188             if (rec->fExternalCounter == 0) {
    189                 REC_TRACE(" Rec [%d] unlock\n", rec->fPrUniqueID);
    190                 rec->fDM->unlock();
    191             }
    192         } else {
    193             SkASSERT(rec->fMalloc != nullptr);
    194         }
    195     }
    196 
    197     bool install(SkBitmap* bitmap) {
    198         SkAutoMutexAcquire ama(fMutex);
    199 
    200         // are we still valid
    201         if (!fDM && !fMalloc) {
    202             REC_TRACE(" Rec: [%d] invalid\n", fPrUniqueID);
    203             return false;
    204         }
    205 
    206         /*
    207             constructor      fExternalCount < 0     fDM->data()
    208             after install    fExternalCount > 0     fDM->data()
    209             after Release    fExternalCount == 0    !fDM->data()
    210         */
    211         if (fDM) {
    212             if (kBeforeFirstInstall_ExternalCounter == fExternalCounter) {
    213                 SkASSERT(fDM->data());
    214             } else if (fExternalCounter > 0) {
    215                 SkASSERT(fDM->data());
    216             } else {
    217                 SkASSERT(fExternalCounter == 0);
    218                 if (!fDM->lock()) {
    219                     REC_TRACE(" Rec [%d] re-lock failed\n", fPrUniqueID);
    220                     fDM.reset(nullptr);
    221                     return false;
    222                 }
    223                 REC_TRACE(" Rec [%d] re-lock succeeded\n", fPrUniqueID);
    224             }
    225             SkASSERT(fDM->data());
    226         }
    227 
    228         bitmap->installPixels(fInfo, fDM ? fDM->data() : fMalloc, fRowBytes, ReleaseProc, this);
    229         SkBitmapCache_setImmutableWithID(bitmap->pixelRef(), fPrUniqueID);
    230 
    231         REC_TRACE(" Rec: [%d] install new pr\n", fPrUniqueID);
    232 
    233         if (kBeforeFirstInstall_ExternalCounter == fExternalCounter) {
    234             fExternalCounter = 1;
    235         } else {
    236             fExternalCounter += 1;
    237         }
    238         SkASSERT(fExternalCounter > 0);
    239         return true;
    240     }
    241 
    242     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
    243         Rec* rec = (Rec*)&baseRec;
    244         SkBitmap* result = (SkBitmap*)contextBitmap;
    245         REC_TRACE(" Rec: [%d] found\n", rec->fPrUniqueID);
    246         return rec->install(result);
    247     }
    248 
    249 private:
    250     BitmapKey   fKey;
    251 
    252     SkMutex     fMutex;
    253 
    254     // either fDM or fMalloc can be non-null, but not both
    255     std::unique_ptr<SkDiscardableMemory> fDM;
    256     void*       fMalloc;
    257 
    258     SkImageInfo fInfo;
    259     size_t      fRowBytes;
    260     uint32_t    fPrUniqueID;
    261 
    262     // This field counts the number of external pixelrefs we have created. They notify us when
    263     // they are destroyed so we can decrement this.
    264     //
    265     //  > 0     we have outstanding pixelrefs
    266     // == 0     we have no outstanding pixelrefs, and can be safely purged
    267     //  < 0     we have been created, but not yet "installed" the first time.
    268     //
    269     int         fExternalCounter;
    270 
    271     enum {
    272         kBeforeFirstInstall_ExternalCounter = -1
    273     };
    274 };
    275 
    276 void SkBitmapCache::PrivateDeleteRec(Rec* rec) { delete rec; }
    277 
    278 SkBitmapCache::RecPtr SkBitmapCache::Alloc(const SkBitmapCacheDesc& desc, const SkImageInfo& info,
    279                                            SkPixmap* pmap) {
    280     // Ensure that the caller is self-consistent:
    281     //  - if they are scaling, the info matches the scaled size
    282     //  - if they are not, the info matches the subset (i.e. the subset is the entire image)
    283     if (desc.fScaledWidth == 0 && desc.fScaledHeight == 0) {
    284         SkASSERT(info.width() == desc.fSubset.width());
    285         SkASSERT(info.height() == desc.fSubset.height());
    286     } else {
    287         SkASSERT(info.width() == desc.fScaledWidth);
    288         SkASSERT(info.height() == desc.fScaledHeight);
    289     }
    290 
    291     const size_t rb = info.minRowBytes();
    292     size_t size = info.computeByteSize(rb);
    293     if (SkImageInfo::ByteSizeOverflowed(size)) {
    294         return nullptr;
    295     }
    296 
    297     std::unique_ptr<SkDiscardableMemory> dm;
    298     void* block = nullptr;
    299 
    300     auto factory = SkResourceCache::GetDiscardableFactory();
    301     if (factory) {
    302         dm.reset(factory(size));
    303     } else {
    304         block = sk_malloc_canfail(size);
    305     }
    306     if (!dm && !block) {
    307         return nullptr;
    308     }
    309     *pmap = SkPixmap(info, dm ? dm->data() : block, rb);
    310     return RecPtr(new Rec(desc, info, rb, std::move(dm), block));
    311 }
    312 
    313 void SkBitmapCache::Add(RecPtr rec, SkBitmap* bitmap) {
    314     SkResourceCache::Add(rec.release(), bitmap);
    315 }
    316 
    317 bool SkBitmapCache::Find(const SkBitmapCacheDesc& desc, SkBitmap* result) {
    318     desc.validate();
    319     return SkResourceCache::Find(BitmapKey(desc), SkBitmapCache::Rec::Finder, result);
    320 }
    321 
    322 //////////////////////////////////////////////////////////////////////////////////////////
    323 //////////////////////////////////////////////////////////////////////////////////////////
    324 
    325 #define CHECK_LOCAL(localCache, localName, globalName, ...) \
    326     ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
    327 
    328 namespace {
    329 static unsigned gMipMapKeyNamespaceLabel;
    330 
    331 struct MipMapKey : public SkResourceCache::Key {
    332 public:
    333     MipMapKey(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode)
    334         : fImageID(imageID)
    335         , fColorMode(static_cast<uint32_t>(colorMode))
    336         , fSubset(subset)
    337     {
    338         SkASSERT(fImageID);
    339         SkASSERT(!subset.isEmpty());
    340         this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(fImageID),
    341                    sizeof(fImageID) + sizeof(fColorMode) + sizeof(fSubset));
    342     }
    343 
    344     uint32_t    fImageID;
    345     uint32_t    fColorMode;
    346     SkIRect     fSubset;
    347 };
    348 
    349 struct MipMapRec : public SkResourceCache::Rec {
    350     MipMapRec(uint32_t imageID, const SkIRect& subset, SkDestinationSurfaceColorMode colorMode,
    351               const SkMipMap* result)
    352         : fKey(imageID, subset, colorMode)
    353         , fMipMap(result)
    354     {
    355         fMipMap->attachToCacheAndRef();
    356     }
    357 
    358     ~MipMapRec() override {
    359         fMipMap->detachFromCacheAndUnref();
    360     }
    361 
    362     const Key& getKey() const override { return fKey; }
    363     size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
    364     const char* getCategory() const override { return "mipmap"; }
    365     SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
    366         return fMipMap->diagnostic_only_getDiscardable();
    367     }
    368 
    369     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
    370         const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
    371         const SkMipMap* mm = SkRef(rec.fMipMap);
    372         // the call to ref() above triggers a "lock" in the case of discardable memory,
    373         // which means we can now check for null (in case the lock failed).
    374         if (nullptr == mm->data()) {
    375             mm->unref();    // balance our call to ref()
    376             return false;
    377         }
    378         // the call must call unref() when they are done.
    379         *(const SkMipMap**)contextMip = mm;
    380         return true;
    381     }
    382 
    383 private:
    384     MipMapKey       fKey;
    385     const SkMipMap* fMipMap;
    386 };
    387 }
    388 
    389 const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc,
    390                                           SkDestinationSurfaceColorMode colorMode,
    391                                           SkResourceCache* localCache) {
    392     SkASSERT(desc.fScaledWidth == 0);
    393     SkASSERT(desc.fScaledHeight == 0);
    394     MipMapKey key(desc.fImageID, desc.fSubset, colorMode);
    395     const SkMipMap* result;
    396 
    397     if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) {
    398         result = nullptr;
    399     }
    400     return result;
    401 }
    402 
    403 static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) {
    404     return localCache ? localCache->GetDiscardableFactory()
    405                       : SkResourceCache::GetDiscardableFactory();
    406 }
    407 
    408 const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src,
    409                                          SkDestinationSurfaceColorMode colorMode,
    410                                          SkResourceCache* localCache) {
    411     SkMipMap* mipmap = SkMipMap::Build(src, colorMode, get_fact(localCache));
    412     if (mipmap) {
    413         MipMapRec* rec = new MipMapRec(src.getGenerationID(), get_bounds_from_bitmap(src),
    414                                        colorMode, mipmap);
    415         CHECK_LOCAL(localCache, add, Add, rec);
    416         src.pixelRef()->notifyAddedToCache();
    417     }
    418     return mipmap;
    419 }
    420