• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getTotalBytesUsed()150     size_t getTotalBytesUsed() const { return fTotalBytesUsed; }
getTotalByteLimit()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 
allocator()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
validate()211     void validate() const {}
212 #endif
213 };
214 #endif
215