• 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 GetBytesUsed();
64     static size_t GetByteLimit();
65     static size_t SetByteLimit(size_t newLimit);
66 
67     static SkBitmap::Allocator* GetAllocator();
68 
69     /**
70      *  Call SkDebugf() with diagnostic information about the state of the cache
71      */
72     static void Dump();
73 
74     ///////////////////////////////////////////////////////////////////////////
75 
76     /**
77      *  Construct the cache to call DiscardableFactory when it
78      *  allocates memory for the pixels. In this mode, the cache has
79      *  not explicit budget, and so methods like getBytesUsed() and
80      *  getByteLimit() will return 0, and setByteLimit will ignore its argument
81      *  and return 0.
82      */
83     SkScaledImageCache(DiscardableFactory);
84 
85     /**
86      *  Construct the cache, allocating memory with malloc, and respect the
87      *  byteLimit, purging automatically when a new image is added to the cache
88      *  that pushes the total bytesUsed over the limit. Note: The limit can be
89      *  changed at runtime with setByteLimit.
90      */
91     SkScaledImageCache(size_t byteLimit);
92 
93     ~SkScaledImageCache();
94 
95     /**
96      *  Search the cache for a matching bitmap (using generationID,
97      *  width, and height as a search key). If found, return it in
98      *  returnedBitmap, and return its ID pointer. Use the returned
99      *  ptr to unlock the cache when you are done using
100      *  returnedBitmap.
101      *
102      *  If a match is not found, returnedBitmap will be unmodifed, and
103      *  NULL will be returned.
104      *
105      *  This is used if there is no scaling or subsetting, for example
106      *  by SkLazyPixelRef.
107      */
108     ID* findAndLock(uint32_t pixelGenerationID, int32_t width, int32_t height,
109                     SkBitmap* returnedBitmap);
110 
111     /**
112      *  Search the cache for a scaled version of original. If found,
113      *  return it in returnedBitmap, and return its ID pointer. Use
114      *  the returned ptr to unlock the cache when you are done using
115      *  returnedBitmap.
116      *
117      *  If a match is not found, returnedBitmap will be unmodifed, and
118      *  NULL will be returned.
119      */
120     ID* findAndLock(const SkBitmap& original, SkScalar scaleX,
121                     SkScalar scaleY, SkBitmap* returnedBitmap);
122     ID* findAndLockMip(const SkBitmap& original,
123                        SkMipMap const** returnedMipMap);
124 
125     /**
126      *  To add a new bitmap (or mipMap) to the cache, call
127      *  AddAndLock. Use the returned ptr to unlock the cache when you
128      *  are done using scaled.
129      *
130      *  Use (generationID, width, and height) or (original, scaleX,
131      *  scaleY) or (original) as a search key
132      */
133     ID* addAndLock(uint32_t pixelGenerationID, int32_t width, int32_t height,
134                    const SkBitmap& bitmap);
135     ID* addAndLock(const SkBitmap& original, SkScalar scaleX,
136                    SkScalar scaleY, const SkBitmap& bitmap);
137     ID* addAndLockMip(const SkBitmap& original, const SkMipMap* mipMap);
138 
139     /**
140      *  Given a non-null ID ptr returned by either findAndLock or addAndLock,
141      *  this releases the associated resources to be available to be purged
142      *  if needed. After this, the cached bitmap should no longer be
143      *  referenced by the caller.
144      */
145     void unlock(ID*);
146 
getBytesUsed()147     size_t getBytesUsed() const { return fBytesUsed; }
getByteLimit()148     size_t getByteLimit() const { return fByteLimit; }
149 
150     /**
151      *  Set the maximum number of bytes available to this cache. If the current
152      *  cache exceeds this new value, it will be purged to try to fit within
153      *  this new limit.
154      */
155     size_t setByteLimit(size_t newLimit);
156 
allocator()157     SkBitmap::Allocator* allocator() const { return fAllocator; };
158 
159     /**
160      *  Call SkDebugf() with diagnostic information about the state of the cache
161      */
162     void dump() const;
163 
164 public:
165     struct Rec;
166     struct Key;
167 private:
168     Rec*    fHead;
169     Rec*    fTail;
170 
171     class Hash;
172     Hash*   fHash;
173 
174     DiscardableFactory  fDiscardableFactory;
175     // the allocator is NULL or one that matches discardables
176     SkBitmap::Allocator* fAllocator;
177 
178     size_t  fBytesUsed;
179     size_t  fByteLimit;
180     int     fCount;
181 
182     Rec* findAndLock(uint32_t generationID, SkScalar sx, SkScalar sy,
183                      const SkIRect& bounds);
184     Rec* findAndLock(const Key& key);
185     ID* addAndLock(Rec* rec);
186 
187     void purgeRec(Rec*);
188     void purgeAsNeeded();
189 
190     // linklist management
191     void moveToHead(Rec*);
192     void addToHead(Rec*);
193     void detach(Rec*);
194 
195     void init();    // called by constructors
196 
197 #ifdef SK_DEBUG
198     void validate() const;
199 #else
validate()200     void validate() const {}
201 #endif
202 };
203 #endif
204