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
13class SkDiscardableMemory;
14class 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 */
26class SkScaledImageCache {
27public:
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
174public:
175    struct Rec;
176    struct Key;
177private:
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