Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2012 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #ifndef ImageDecodingStore_h
     27 #define ImageDecodingStore_h
     28 
     29 #include "SkSize.h"
     30 #include "SkTypes.h"
     31 #include "platform/PlatformExport.h"
     32 #include "platform/graphics/DiscardablePixelRef.h"
     33 #include "platform/graphics/ScaledImageFragment.h"
     34 #include "platform/graphics/skia/SkSizeHash.h"
     35 #include "platform/image-decoders/ImageDecoder.h"
     36 
     37 #include "wtf/DoublyLinkedList.h"
     38 #include "wtf/HashSet.h"
     39 #include "wtf/OwnPtr.h"
     40 #include "wtf/PassOwnPtr.h"
     41 #include "wtf/ThreadingPrimitives.h"
     42 #include "wtf/Vector.h"
     43 
     44 namespace WebCore {
     45 
     46 class ImageFrameGenerator;
     47 class SharedBuffer;
     48 
     49 // FUNCTION
     50 //
     51 // ImageDecodingStore is a class used to manage image cache objects. There are two
     52 // types of cache objects stored:
     53 //
     54 // 1. Image objects
     55 //    Each image object belongs to one frame decoded and/or resampled from an image
     56 //    file. The image object can be complete or partial. Complete means the image
     57 //    is fully decoded and will not mutate in future decoding passes. It can have
     58 //    multiple concurrent users. A partial image object has only one user.
     59 //
     60 // 2. Decoder objects
     61 //    A decoder object contains an image decoder. This allows decoding to resume
     62 //    from previous states. There can be one user per one decoder object at any
     63 //    time.
     64 //
     65 // EXTERNAL OBJECTS
     66 //
     67 // ScaledImageFragment
     68 //   A cached image object. Contains the bitmap and information about the bitmap
     69 //   image.
     70 //
     71 // ImageDecoder
     72 //   A decoder object. It is used to decode raw data into bitmap images.
     73 //
     74 // ImageFrameGenerator
     75 //   This is a direct user of this cache. Responsible for generating bitmap images
     76 //   using an ImageDecoder. It contains encoded image data and is used to represent
     77 //   one image file. It is used to index image and decoder objects in the cache.
     78 //
     79 // LazyDecodingPixelRef
     80 //   A read only user of this cache.
     81 //
     82 // THREAD SAFETY
     83 //
     84 // All public methods can be used on any thread.
     85 
     86 class PLATFORM_EXPORT ImageDecodingStore {
     87 public:
     88     static PassOwnPtr<ImageDecodingStore> create() { return adoptPtr(new ImageDecodingStore); }
     89     ~ImageDecodingStore();
     90 
     91     static ImageDecodingStore* instance();
     92     static void initializeOnce();
     93     static void shutdown();
     94 
     95     // Why do we need this?
     96     // ImageDecodingStore is used in two code paths:
     97     // 1. Android uses this to cache both images and decoders.
     98     // 2. Skia discardable memory path has its own cache. We still want cache
     99     //    decoders but not images because Skia will take care of it.
    100     // Because of the two use cases we want to just disable image caching.
    101     //
    102     // FIXME: It is weird to have this behavior. We want to remove image
    103     // caching from this class once the transition to Skia discardable memory
    104     // is complete.
    105     static void setImageCachingEnabled(bool);
    106 
    107     // Access a complete cached image object. A complete cached image object is
    108     // indexed by the origin (ImageFrameGenerator), scaled size and frame index
    109     // within the image file.
    110     // Return true if the cache object is found.
    111     // Return false if the cache object cannot be found or it is incomplete.
    112     bool lockCache(const ImageFrameGenerator*, const SkISize& scaledSize, size_t index, const ScaledImageFragment**);
    113     void unlockCache(const ImageFrameGenerator*, const ScaledImageFragment*);
    114     const ScaledImageFragment* insertAndLockCache(const ImageFrameGenerator*, PassOwnPtr<ScaledImageFragment>);
    115 
    116     // Access a cached decoder object. A decoder is indexed by origin (ImageFrameGenerator)
    117     // and scaled size. Return true if the cached object is found.
    118     bool lockDecoder(const ImageFrameGenerator*, const SkISize& scaledSize, ImageDecoder**);
    119     void unlockDecoder(const ImageFrameGenerator*, const ImageDecoder*);
    120     void insertDecoder(const ImageFrameGenerator*, PassOwnPtr<ImageDecoder>, bool isDiscardable);
    121     void removeDecoder(const ImageFrameGenerator*, const ImageDecoder*);
    122 
    123     // Locks the cache for safety, but does not attempt to lock the object we're checking for.
    124     bool isCached(const ImageFrameGenerator*, const SkISize& scaledSize, size_t index);
    125 
    126     // Remove all cache entries indexed by ImageFrameGenerator.
    127     void removeCacheIndexedByGenerator(const ImageFrameGenerator*);
    128 
    129     void clear();
    130     void setCacheLimitInBytes(size_t);
    131     size_t memoryUsageInBytes();
    132     int cacheEntries();
    133     int imageCacheEntries();
    134     int decoderCacheEntries();
    135 
    136 private:
    137     // Image cache entry is identified by:
    138     // 1. Pointer to ImageFrameGenerator.
    139     // 2. Size of the image.
    140     // 3. Frame index.
    141     // 4. Frame generation. Increments on each progressive decode.
    142     //
    143     // The use of generation ID is to allow multiple versions of an image frame
    144     // be stored in the cache. Each generation comes from a progressive decode.
    145     //
    146     // Decoder entries are identified by (1) and (2) only.
    147     typedef std::pair<const ImageFrameGenerator*, SkISize> DecoderCacheKey;
    148     typedef std::pair<size_t, size_t> IndexAndGeneration;
    149     typedef std::pair<DecoderCacheKey, IndexAndGeneration> ImageCacheKey;
    150 
    151     // Base class for all cache entries.
    152     class CacheEntry : public DoublyLinkedListNode<CacheEntry> {
    153         friend class WTF::DoublyLinkedListNode<CacheEntry>;
    154     public:
    155         enum CacheType {
    156             TypeImage,
    157             TypeDecoder,
    158         };
    159 
    160         CacheEntry(const ImageFrameGenerator* generator, int useCount, bool isDiscardable)
    161             : m_generator(generator)
    162             , m_useCount(useCount)
    163             , m_isDiscardable(isDiscardable)
    164             , m_prev(0)
    165             , m_next(0)
    166         {
    167         }
    168 
    169         virtual ~CacheEntry()
    170         {
    171             ASSERT(!m_useCount);
    172         }
    173 
    174         const ImageFrameGenerator* generator() const { return m_generator; }
    175         int useCount() const { return m_useCount; }
    176         void incrementUseCount() { ++m_useCount; }
    177         void decrementUseCount() { --m_useCount; ASSERT(m_useCount >= 0); }
    178         bool isDiscardable() const { return m_isDiscardable; }
    179 
    180         // FIXME: getSafeSize() returns size in bytes truncated to a 32-bits integer.
    181         //        Find a way to get the size in 64-bits.
    182         virtual size_t memoryUsageInBytes() const = 0;
    183         virtual CacheType type() const = 0;
    184 
    185     protected:
    186         const ImageFrameGenerator* m_generator;
    187         int m_useCount;
    188         bool m_isDiscardable;
    189 
    190     private:
    191         CacheEntry* m_prev;
    192         CacheEntry* m_next;
    193     };
    194 
    195     class ImageCacheEntry : public CacheEntry {
    196     public:
    197         static PassOwnPtr<ImageCacheEntry> createAndUse(const ImageFrameGenerator* generator, PassOwnPtr<ScaledImageFragment> image)
    198         {
    199             return adoptPtr(new ImageCacheEntry(generator, 1, image));
    200         }
    201 
    202         ImageCacheEntry(const ImageFrameGenerator* generator, int count, PassOwnPtr<ScaledImageFragment> image)
    203             : CacheEntry(generator, count, DiscardablePixelRef::isDiscardable(image->bitmap().pixelRef()))
    204             , m_cachedImage(image)
    205         {
    206         }
    207 
    208         // FIXME: getSafeSize() returns size in bytes truncated to a 32-bits integer.
    209         //        Find a way to get the size in 64-bits.
    210         virtual size_t memoryUsageInBytes() const { return cachedImage()->bitmap().getSafeSize(); }
    211         virtual CacheType type() const { return TypeImage; }
    212 
    213         static ImageCacheKey makeCacheKey(const ImageFrameGenerator* generator, const SkISize& size, size_t index, size_t generation)
    214         {
    215             return std::make_pair(std::make_pair(generator, size), std::make_pair(index, generation));
    216         }
    217         ImageCacheKey cacheKey() const { return makeCacheKey(m_generator, m_cachedImage->scaledSize(), m_cachedImage->index(), m_cachedImage->generation()); }
    218         const ScaledImageFragment* cachedImage() const { return m_cachedImage.get(); }
    219         ScaledImageFragment* cachedImage() { return m_cachedImage.get(); }
    220 
    221     private:
    222         OwnPtr<ScaledImageFragment> m_cachedImage;
    223     };
    224 
    225     class DecoderCacheEntry : public CacheEntry {
    226     public:
    227         static PassOwnPtr<DecoderCacheEntry> create(const ImageFrameGenerator* generator, PassOwnPtr<ImageDecoder> decoder, bool isDiscardable)
    228         {
    229             return adoptPtr(new DecoderCacheEntry(generator, 0, decoder, isDiscardable));
    230         }
    231 
    232         DecoderCacheEntry(const ImageFrameGenerator* generator, int count, PassOwnPtr<ImageDecoder> decoder, bool isDiscardable)
    233             : CacheEntry(generator, count, isDiscardable)
    234             , m_cachedDecoder(decoder)
    235             , m_size(SkISize::Make(m_cachedDecoder->decodedSize().width(), m_cachedDecoder->decodedSize().height()))
    236         {
    237         }
    238 
    239         virtual size_t memoryUsageInBytes() const { return m_size.width() * m_size.height() * 4; }
    240         virtual CacheType type() const { return TypeDecoder; }
    241 
    242         static DecoderCacheKey makeCacheKey(const ImageFrameGenerator* generator, const SkISize& size)
    243         {
    244             return std::make_pair(generator, size);
    245         }
    246         static DecoderCacheKey makeCacheKey(const ImageFrameGenerator* generator, const ImageDecoder* decoder)
    247         {
    248             return std::make_pair(generator, SkISize::Make(decoder->decodedSize().width(), decoder->decodedSize().height()));
    249         }
    250         DecoderCacheKey cacheKey() const { return makeCacheKey(m_generator, m_size); }
    251         ImageDecoder* cachedDecoder() const { return m_cachedDecoder.get(); }
    252 
    253     private:
    254         OwnPtr<ImageDecoder> m_cachedDecoder;
    255         SkISize m_size;
    256     };
    257 
    258     ImageDecodingStore();
    259 
    260     void prune();
    261 
    262     // These helper methods are called while m_mutex is locked.
    263 
    264     // Find and lock a cache entry, and return true on success.
    265     // Memory of the cache entry can be discarded, in which case it is saved in
    266     // deletionList.
    267     bool lockCacheEntryInternal(ImageCacheEntry*, const ScaledImageFragment**, Vector<OwnPtr<CacheEntry> >* deletionList);
    268 
    269     template<class T, class U, class V> void insertCacheInternal(PassOwnPtr<T> cacheEntry, U* cacheMap, V* identifierMap);
    270 
    271     // Helper method to remove a cache entry. Ownership is transferred to
    272     // deletionList. Use of Vector<> is handy when removing multiple entries.
    273     template<class T, class U, class V> void removeFromCacheInternal(const T* cacheEntry, U* cacheMap, V* identifierMap, Vector<OwnPtr<CacheEntry> >* deletionList);
    274 
    275     // Helper method to remove a cache entry. Uses the templated version base on
    276     // the type of cache entry.
    277     void removeFromCacheInternal(const CacheEntry*, Vector<OwnPtr<CacheEntry> >* deletionList);
    278 
    279     // Helper method to remove all cache entries associated with a ImageFraneGenerator.
    280     // Ownership of cache entries is transferred to deletionList.
    281     template<class U, class V> void removeCacheIndexedByGeneratorInternal(U* cacheMap, V* identifierMap, const ImageFrameGenerator*, Vector<OwnPtr<CacheEntry> >* deletionList);
    282 
    283     // Helper method to remove cache entry pointers from the LRU list.
    284     void removeFromCacheListInternal(const Vector<OwnPtr<CacheEntry> >& deletionList);
    285 
    286     // A doubly linked list that maintains usage history of cache entries.
    287     // This is used for eviction of old entries.
    288     // Head of this list is the least recently used cache entry.
    289     // Tail of this list is the most recently used cache entry.
    290     DoublyLinkedList<CacheEntry> m_orderedCacheList;
    291 
    292     // A lookup table for all image cache objects. Owns all image cache objects.
    293     typedef HashMap<ImageCacheKey, OwnPtr<ImageCacheEntry> > ImageCacheMap;
    294     ImageCacheMap m_imageCacheMap;
    295 
    296     // A lookup table for all decoder cache objects. Owns all decoder cache objects.
    297     typedef HashMap<DecoderCacheKey, OwnPtr<DecoderCacheEntry> > DecoderCacheMap;
    298     DecoderCacheMap m_decoderCacheMap;
    299 
    300     // A lookup table to map ImageFrameGenerator to all associated image
    301     // cache keys.
    302     typedef HashSet<ImageCacheKey> ImageCacheKeySet;
    303     typedef HashMap<const ImageFrameGenerator*, ImageCacheKeySet> ImageCacheKeyMap;
    304     ImageCacheKeyMap m_imageCacheKeyMap;
    305 
    306     // A lookup table to map ImageFrameGenerator to all associated
    307     // decoder cache keys.
    308     typedef HashSet<DecoderCacheKey> DecoderCacheKeySet;
    309     typedef HashMap<const ImageFrameGenerator*, DecoderCacheKeySet> DecoderCacheKeyMap;
    310     DecoderCacheKeyMap m_decoderCacheKeyMap;
    311 
    312     size_t m_heapLimitInBytes;
    313     size_t m_heapMemoryUsageInBytes;
    314     size_t m_discardableMemoryUsageInBytes;
    315 
    316     // Protect concurrent access to these members:
    317     //   m_orderedCacheList
    318     //   m_imageCacheMap, m_decoderCacheMap and all CacheEntrys stored in it
    319     //   m_imageCacheKeyMap
    320     //   m_decoderCacheKeyMap
    321     //   m_heapLimitInBytes
    322     //   m_heapMemoryUsageInBytes
    323     //   m_discardableMemoryUsageInBytes
    324     // This mutex also protects calls to underlying skBitmap's
    325     // lockPixels()/unlockPixels() as they are not threadsafe.
    326     Mutex m_mutex;
    327 };
    328 
    329 } // namespace WebCore
    330 
    331 #endif
    332