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