Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(473)

Side by Side Diff: src/core/SkScaledImageCache.cpp

Issue 20005003: add scaledimagecache (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/core/SkScaledImageCache.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #include "SkScaledImageCache.h"
2 #include "SkPixelRef.h"
3 #include "SkRect.h"
4
5 static const size_t DEF_BYTE_LIMIT = 2 * 1024 * 1024;
ernstm 2013/07/23 06:36:50 Two megabyte is quite low. Should we set this to a
reed1 2013/07/23 14:50:29 There is now a define that chrome can set in skia.
6
7 struct Key {
8 bool init(const SkBitmap& bm, SkScalar scaleX, SkScalar scaleY) {
9 SkPixelRef* pr = bm.pixelRef();
10 if (!pr) {
11 return false;
12 }
13
14 size_t offset = bm.pixelRefOffset();
15 size_t rowBytes = bm.rowBytes();
16 int x = (offset % rowBytes) >> 2;
17 int y = offset / rowBytes;
18
19 fGenID = pr->getGenerationID();
20 fBounds.set(x, y, x + bm.width(), y + bm.height());
21 fScaleX = scaleX;
22 fScaleY = scaleY;
23 return true;
24 }
25
26 bool operator<(const Key& other) {
27 const uint32_t* a = &fGenID;
28 const uint32_t* b = &other.fGenID;
29 for (int i = 0; i < 7; ++i) {
30 if (a[i] < b[i]) {
31 return true;
32 }
33 if (a[i] > b[i]) {
34 return false;
35 }
36 }
37 return false;
38 }
39
40 bool operator==(const Key& other) {
41 const uint32_t* a = &fGenID;
42 const uint32_t* b = &other.fGenID;
43 for (int i = 0; i < 7; ++i) {
44 if (a[i] != b[i]) {
45 return false;
46 }
47 }
48 return true;
49 }
50
51 uint32_t fGenID;
52 SkIRect fBounds;
53 float fScaleX;
54 float fScaleY;
55 };
56
57 struct SkScaledImageCache::Rec {
58 Rec(const Key& key, const SkBitmap& bm) : fKey(key), fBitmap(bm) {
59 fLockCount = 1;
60 }
61
62 size_t bytesUsed() const {
63 return fBitmap.getSize();
64 }
65
66 Rec* fNext;
67 Rec* fPrev;
68
69 int32_t fLockCount;
70 Key fKey;
71 SkBitmap fBitmap;
72 };
73
74 SkScaledImageCache::SkScaledImageCache() {
75 fHead = NULL;
76 fTail = NULL;
77 fBytesUsed = 0;
78 fByteLimit = DEF_BYTE_LIMIT;
79 fCount = 0;
80 }
81
82 SkScaledImageCache::~SkScaledImageCache() {
83 Rec* rec = fHead;
84 while (rec) {
85 Rec* next = rec->fNext;
86 SkDELETE(rec);
87 rec = next;
88 }
89 }
90
91 SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig,
humper 2013/07/23 01:25:44 Possibly worth a comment here saying that any nece
reed1 2013/07/23 14:50:29 Done.
92 SkScalar scaleX,
93 SkScalar scaleY,
94 SkBitmap* scaled) {
95 Key key;
96 if (!key.init(orig, scaleX, scaleY)) {
97 return NULL;
98 }
99
100 Rec* rec = fHead;
101 while (rec != NULL) {
102 if (rec->fKey == key) {
103 this->moveToHead(rec); // for our LRU
104 rec->fLockCount += 1;
105 *scaled = rec->fBitmap;
106 // SkDebugf("Found: [%d %d] %d\n", rec->fBitmap.width(), rec->fBitmap .height(), rec->fLockCount);
107 return (ID*)rec;
108 }
109 rec = rec->fNext;
110 }
111 return NULL;
112 }
113
114 SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig,
humper 2013/07/23 01:25:44 same as above re: comment
reed1 2013/07/23 14:50:29 Done.
115 SkScalar scaleX,
116 SkScalar scaleY,
117 const SkBitmap& scaled) {
118 Key key;
119 if (!key.init(orig, scaleX, scaleY)) {
120 return NULL;
121 }
122
123 Rec* rec = SkNEW_ARGS(Rec, (key, scaled));
124 this->addToHead(rec);
125 SkASSERT(1 == rec->fLockCount);
126
127 // SkDebugf("Added: [%d %d]\n", rec->fBitmap.width(), rec->fBitmap.height());
128
129 // We may (now) be overbudget, so see if we need to purge something.
130 this->purgeAsNeeded();
131 return (ID*)rec;
132 }
133
134 void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) {
humper 2013/07/23 01:25:44 ditto above re: comment
reed1 2013/07/23 14:50:29 Done.
135 SkASSERT(id);
136
137 #ifdef SK_DEBUG
138 {
139 bool found = false;
140 Rec* rec = fHead;
141 while (rec != NULL) {
142 if ((ID*)rec == id) {
143 found = true;
144 break;
145 }
146 rec = rec->fNext;
147 }
148 SkASSERT(found);
149 }
150 #endif
151 Rec* rec = (Rec*)id;
152 SkASSERT(rec->fLockCount > 0);
153 rec->fLockCount -= 1;
154
155 // SkDebugf("Unlock: [%d %d] %d\n", rec->fBitmap.width(), rec->fBitmap.height (), rec->fLockCount);
156
157 // we may have been over-budget, but now have released something, so check
158 // if we should purge.
159 if (0 == rec->fLockCount) {
160 this->purgeAsNeeded();
161 }
162 }
163
164 void SkScaledImageCache::purgeAsNeeded() {
165 size_t byteLimit = fByteLimit;
166 size_t bytesUsed = fBytesUsed;
167
168 Rec* rec = fTail;
169 while (rec) {
170 if (bytesUsed < byteLimit) {
171 break;
172 }
173 Rec* prev = rec->fPrev;
174 if (0 == rec->fLockCount) {
175 // SkDebugf("Purge: [%d %d] %d\n", rec->fBitmap.width(), rec->fBitmap .height(), fCount);
176 size_t used = rec->bytesUsed();
177 SkASSERT(used <= bytesUsed);
178 bytesUsed -= used;
179 this->detach(rec);
180 SkDELETE(rec);
181 fCount -= 1;
182 }
183 rec = prev;
184 }
185 fBytesUsed = bytesUsed;
186 }
187
188 ///////////////////////////////////////////////////////////////////////////////
189
190 void SkScaledImageCache::detach(Rec* rec) {
191 Rec* prev = rec->fPrev;
192 Rec* next = rec->fNext;
193
194 if (!prev) {
195 SkASSERT(fHead == rec);
196 fHead = next;
197 } else {
198 prev->fNext = next;
199 }
200
201 if (!next) {
202 fTail = prev;
203 } else {
204 next->fPrev = prev;
205 }
206
207 rec->fNext = rec->fPrev = NULL;
208 }
209
210 void SkScaledImageCache::moveToHead(Rec* rec) {
211 if (fHead == rec) {
212 return;
213 }
214
215 SkASSERT(fHead);
216 SkASSERT(fTail);
217
218 this->validate();
219
220 if (3 == fCount)
221 SkDebugf("");
humper 2013/07/23 01:25:44 Obviously the debug statements are intended to be
reed1 2013/07/23 14:50:29 Done.
222 this->detach(rec);
223
224 fHead->fPrev = rec;
225 rec->fNext = fHead;
226 fHead = rec;
227
228 this->validate();
229 }
230
231 void SkScaledImageCache::addToHead(Rec* rec) {
232 this->validate();
233
234 rec->fPrev = NULL;
235 rec->fNext = fHead;
236 if (fHead) {
237 fHead->fPrev = rec;
238 }
239 fHead = rec;
240 if (!fTail) {
241 fTail = rec;
242 }
243 fBytesUsed += rec->bytesUsed();
244 fCount += 1;
245
246 this->validate();
247 }
248
249 #ifdef SK_DEBUG
250 void SkScaledImageCache::validate() const {
251 if (NULL == fHead) {
252 SkASSERT(NULL == fTail);
253 SkASSERT(0 == fBytesUsed);
254 return;
255 }
256
257 if (fHead == fTail) {
258 SkASSERT(NULL == fHead->fPrev);
259 SkASSERT(NULL == fHead->fNext);
260 SkASSERT(fHead->bytesUsed() == fBytesUsed);
261 return;
262 }
263
264 SkASSERT(NULL == fHead->fPrev);
265 SkASSERT(NULL != fHead->fNext);
266 SkASSERT(NULL == fTail->fNext);
267 SkASSERT(NULL != fTail->fPrev);
268
269 size_t used = 0;
270 int count = 0;
271 const Rec* rec = fHead;
272 while (rec) {
273 count += 1;
274 used += rec->bytesUsed();
275 SkASSERT(used <= fBytesUsed);
276 rec = rec->fNext;
277 }
278 SkASSERT(fCount == count);
279
280 rec = fTail;
281 while (rec) {
282 SkASSERT(count > 0);
283 count -= 1;
284 SkASSERT(used >= rec->bytesUsed());
285 used -= rec->bytesUsed();
286 rec = rec->fPrev;
287 }
288
289 SkASSERT(0 == count);
290 SkASSERT(0 == used);
291 }
292 #endif
293
294 ///////////////////////////////////////////////////////////////////////////////
295
296 #include "SkThread.h"
297
298 static SkMutex gMutex;
299
300 static SkScaledImageCache* get_cache() {
301 static SkScaledImageCache* gCache;
humper 2013/07/23 01:25:44 I know the standard says that this will be initial
reed1 2013/07/23 14:50:29 I don't know if anything is written in the doc, bu
302 if (!gCache) {
303 gCache = SkNEW(SkScaledImageCache);
304 }
305 return gCache;
306 }
307
308 SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const SkBitmap& orig,
309 SkScalar scaleX,
310 SkScalar scaleY,
311 SkBitmap* scaled) {
312 SkAutoMutexAcquire am(gMutex);
313 return get_cache()->findAndLock(orig, scaleX, scaleY, scaled);
314 }
315
316 SkScaledImageCache::ID* SkScaledImageCache::AddAndLock(const SkBitmap& orig,
317 SkScalar scaleX,
318 SkScalar scaleY,
319 const SkBitmap& scaled) {
320 SkAutoMutexAcquire am(gMutex);
321 return get_cache()->addAndLock(orig, scaleX, scaleY, scaled);
322 }
323
324 void SkScaledImageCache::Unlock(SkScaledImageCache::ID* id) {
325 SkAutoMutexAcquire am(gMutex);
326 return get_cache()->unlock(id);
327 }
328
329 size_t SkScaledImageCache::GetByteLimit() {
330 SkAutoMutexAcquire am(gMutex);
331 return get_cache()->fByteLimit;
332 }
333
334 size_t SkScaledImageCache::SetByteLimit(size_t newLimit) {
335 SkAutoMutexAcquire am(gMutex);
336 SkScaledImageCache* cache = get_cache();
337 size_t prevLimit = cache->fByteLimit;
338 cache->fByteLimit = newLimit;
339 cache->purgeAsNeeded();
340 return prevLimit;
341 }
342
343 size_t SkScaledImageCache::GetBytesUsed() {
344 SkAutoMutexAcquire am(gMutex);
345 return get_cache()->fBytesUsed;
346 }
347
OLDNEW
« no previous file with comments | « src/core/SkScaledImageCache.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698