Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2013 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 #ifndef SkScaledImageCache_DEFINED
      9 #define SkScaledImageCache_DEFINED
     10 
     11 #include "SkBitmap.h"
     12 
     13 class SkDiscardableMemory;
     14 class SkMipMap;
     15 
     16 /**
     17  *  Cache object for bitmaps (with possible scale in X Y as part of the key).
     18  *
     19  *  Multiple caches can be instantiated, but each instance is not implicitly
     20  *  thread-safe, so if a given instance is to be shared across threads, the
     21  *  caller must manage the access itself (e.g. via a mutex).
     22  *
     23  *  As a convenience, a global instance is also defined, which can be safely
     24  *  access across threads via the static methods (e.g. FindAndLock, etc.).
     25  */
     26 class SkScaledImageCache {
     27 public:
     28     struct ID;
     29 
     30     /**
     31      *  Returns a locked/pinned SkDiscardableMemory instance for the specified
     32      *  number of bytes, or NULL on failure.
     33      */
     34     typedef SkDiscardableMemory* (*DiscardableFactory)(size_t bytes);
     35 
     36     /*
     37      *  The following static methods are thread-safe wrappers around a global
     38      *  instance of this cache.
     39      */
     40 
     41     static ID* FindAndLock(uint32_t pixelGenerationID,
     42                            int32_t width,
     43                            int32_t height,
     44                            SkBitmap* returnedBitmap);
     45 
     46     static ID* FindAndLock(const SkBitmap& original, SkScalar scaleX,
     47                            SkScalar scaleY, SkBitmap* returnedBitmap);
     48     static ID* FindAndLockMip(const SkBitmap& original,
     49                               SkMipMap const** returnedMipMap);
     50 
     51 
     52     static ID* AddAndLock(uint32_t pixelGenerationID,
     53                           int32_t width,
     54                           int32_t height,
     55                           const SkBitmap& bitmap);
     56 
     57     static ID* AddAndLock(const SkBitmap& original, SkScalar scaleX,
     58                           SkScalar scaleY, const SkBitmap& bitmap);
     59     static ID* AddAndLockMip(const SkBitmap& original, const SkMipMap* mipMap);
     60 
     61     static void Unlock(ID*);
     62 
     63     static size_t GetTotalBytesUsed();
     64     static size_t GetTotalByteLimit();
     65     static size_t SetTotalByteLimit(size_t newLimit);
     66 
     67     static size_t SetSingleAllocationByteLimit(size_t);
     68     static size_t GetSingleAllocationByteLimit();
     69 
     70     static SkBitmap::Allocator* GetAllocator();
     71 
     72     /**
     73      *  Call SkDebugf() with diagnostic information about the state of the cache
     74      */
     75     static void Dump();
     76 
     77     ///////////////////////////////////////////////////////////////////////////
     78 
     79     /**
     80      *  Construct the cache to call DiscardableFactory when it
     81      *  allocates memory for the pixels. In this mode, the cache has
     82      *  not explicit budget, and so methods like getTotalBytesUsed()
     83      *  and getTotalByteLimit() will return 0, and setTotalByteLimit
     84      *  will ignore its argument and return 0.
     85      */
     86     SkScaledImageCache(DiscardableFactory);
     87 
     88     /**
     89      *  Construct the cache, allocating memory with malloc, and respect the
     90      *  byteLimit, purging automatically when a new image is added to the cache
     91      *  that pushes the total bytesUsed over the limit. Note: The limit can be
     92      *  changed at runtime with setTotalByteLimit.
     93      */
     94     SkScaledImageCache(size_t byteLimit);
     95 
     96     ~SkScaledImageCache();
     97 
     98     /**
     99      *  Search the cache for a matching bitmap (using generationID,
    100      *  width, and height as a search key). If found, return it in
    101      *  returnedBitmap, and return its ID pointer. Use the returned
    102      *  ptr to unlock the cache when you are done using
    103      *  returnedBitmap.
    104      *
    105      *  If a match is not found, returnedBitmap will be unmodifed, and
    106      *  NULL will be returned.
    107      *
    108      *  This is used if there is no scaling or subsetting, for example
    109      *  by SkLazyPixelRef.
    110      */
    111     ID* findAndLock(uint32_t pixelGenerationID, int32_t width, int32_t height,
    112                     SkBitmap* returnedBitmap);
    113 
    114     /**
    115      *  Search the cache for a scaled version of original. If found,
    116      *  return it in returnedBitmap, and return its ID pointer. Use
    117      *  the returned ptr to unlock the cache when you are done using
    118      *  returnedBitmap.
    119      *
    120      *  If a match is not found, returnedBitmap will be unmodifed, and
    121      *  NULL will be returned.
    122      */
    123     ID* findAndLock(const SkBitmap& original, SkScalar scaleX,
    124                     SkScalar scaleY, SkBitmap* returnedBitmap);
    125     ID* findAndLockMip(const SkBitmap& original,
    126                        SkMipMap const** returnedMipMap);
    127 
    128     /**
    129      *  To add a new bitmap (or mipMap) to the cache, call
    130      *  AddAndLock. Use the returned ptr to unlock the cache when you
    131      *  are done using scaled.
    132      *
    133      *  Use (generationID, width, and height) or (original, scaleX,
    134      *  scaleY) or (original) as a search key
    135      */
    136     ID* addAndLock(uint32_t pixelGenerationID, int32_t width, int32_t height,
    137                    const SkBitmap& bitmap);
    138     ID* addAndLock(const SkBitmap& original, SkScalar scaleX,
    139                    SkScalar scaleY, const SkBitmap& bitmap);
    140     ID* addAndLockMip(const SkBitmap& original, const SkMipMap* mipMap);
    141 
    142     /**
    143      *  Given a non-null ID ptr returned by either findAndLock or addAndLock,
    144      *  this releases the associated resources to be available to be purged
    145      *  if needed. After this, the cached bitmap should no longer be
    146      *  referenced by the caller.
    147      */
    148     void unlock(ID*);
    149 
    150     size_t getTotalBytesUsed() const { return fTotalBytesUsed; }
    151     size_t getTotalByteLimit() const { return fTotalByteLimit; }
    152 
    153     /**
    154      *  This is respected by SkBitmapProcState::possiblyScaleImage.
    155      *  0 is no maximum at all; this is the default.
    156      *  setSingleAllocationByteLimit() returns the previous value.
    157      */
    158     size_t setSingleAllocationByteLimit(size_t maximumAllocationSize);
    159     size_t getSingleAllocationByteLimit() const;
    160     /**
    161      *  Set the maximum number of bytes available to this cache. If the current
    162      *  cache exceeds this new value, it will be purged to try to fit within
    163      *  this new limit.
    164      */
    165     size_t setTotalByteLimit(size_t newLimit);
    166 
    167     SkBitmap::Allocator* allocator() const { return fAllocator; };
    168 
    169     /**
    170      *  Call SkDebugf() with diagnostic information about the state of the cache
    171      */
    172     void dump() const;
    173 
    174 public:
    175     struct Rec;
    176     struct Key;
    177 private:
    178     Rec*    fHead;
    179     Rec*    fTail;
    180 
    181     class Hash;
    182     Hash*   fHash;
    183 
    184     DiscardableFactory  fDiscardableFactory;
    185     // the allocator is NULL or one that matches discardables
    186     SkBitmap::Allocator* fAllocator;
    187 
    188     size_t  fTotalBytesUsed;
    189     size_t  fTotalByteLimit;
    190     size_t  fSingleAllocationByteLimit;
    191     int     fCount;
    192 
    193     Rec* findAndLock(uint32_t generationID, SkScalar sx, SkScalar sy,
    194                      const SkIRect& bounds);
    195     Rec* findAndLock(const Key& key);
    196     ID* addAndLock(Rec* rec);
    197 
    198     void purgeRec(Rec*);
    199     void purgeAsNeeded();
    200 
    201     // linklist management
    202     void moveToHead(Rec*);
    203     void addToHead(Rec*);
    204     void detach(Rec*);
    205 
    206     void init();    // called by constructors
    207 
    208 #ifdef SK_DEBUG
    209     void validate() const;
    210 #else
    211     void validate() const {}
    212 #endif
    213 };
    214 #endif
    215