OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkScaledImageCache.h" | 8 #include "SkScaledImageCache.h" |
9 #include "SkMipMap.h" | 9 #include "SkMipMap.h" |
10 #include "SkOnce.h" | 10 #include "SkOnce.h" |
11 #include "SkPixelRef.h" | 11 #include "SkPixelRef.h" |
12 #include "SkRect.h" | 12 #include "SkRect.h" |
13 | 13 |
14 // This can be defined by the caller's build system | |
15 //#define SK_USE_DISCARDABLE_SCALEDIMAGECACHE | |
16 | |
17 #ifndef SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT | |
18 # define SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT 1024 | |
hal.canary
2013/12/09 18:23:27
I assume you expect clients to set this number lar
reed1
2013/12/09 18:43:48
Or smaller
| |
19 #endif | |
20 | |
14 #ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT | 21 #ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT |
15 #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) | 22 #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) |
16 #endif | 23 #endif |
17 | 24 |
18 static inline SkScaledImageCache::ID* rec_to_id(SkScaledImageCache::Rec* rec) { | 25 static inline SkScaledImageCache::ID* rec_to_id(SkScaledImageCache::Rec* rec) { |
19 return reinterpret_cast<SkScaledImageCache::ID*>(rec); | 26 return reinterpret_cast<SkScaledImageCache::ID*>(rec); |
20 } | 27 } |
21 | 28 |
22 static inline SkScaledImageCache::Rec* id_to_rec(SkScaledImageCache::ID* id) { | 29 static inline SkScaledImageCache::Rec* id_to_rec(SkScaledImageCache::ID* id) { |
23 return reinterpret_cast<SkScaledImageCache::Rec*>(id); | 30 return reinterpret_cast<SkScaledImageCache::Rec*>(id); |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
157 static inline SkScaledImageCache::Rec* find_rec_in_list( | 164 static inline SkScaledImageCache::Rec* find_rec_in_list( |
158 SkScaledImageCache::Rec* head, const Key & key) { | 165 SkScaledImageCache::Rec* head, const Key & key) { |
159 SkScaledImageCache::Rec* rec = head; | 166 SkScaledImageCache::Rec* rec = head; |
160 while ((rec != NULL) && (rec->fKey != key)) { | 167 while ((rec != NULL) && (rec->fKey != key)) { |
161 rec = rec->fNext; | 168 rec = rec->fNext; |
162 } | 169 } |
163 return rec; | 170 return rec; |
164 } | 171 } |
165 #endif | 172 #endif |
166 | 173 |
167 SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { | 174 void SkScaledImageCache::init() { |
168 fHead = NULL; | 175 fHead = NULL; |
169 fTail = NULL; | 176 fTail = NULL; |
170 #ifdef USE_HASH | 177 #ifdef USE_HASH |
171 fHash = new Hash; | 178 fHash = new Hash; |
172 #else | 179 #else |
173 fHash = NULL; | 180 fHash = NULL; |
174 #endif | 181 #endif |
175 fBytesUsed = 0; | 182 fBytesUsed = 0; |
183 fCount = 0; | |
184 fAllocator = NULL; | |
185 | |
186 // One of these should be explicit set by the caller after we return. | |
187 fByteLimit = 0; | |
188 fDiscardableFactory = NULL; | |
189 } | |
190 | |
191 #include "SkDiscardableMemory.h" | |
192 | |
193 class SkOneShotDiscardablePixelRef : public SkPixelRef { | |
194 public: | |
195 // Ownership of the discardablememory is transfered to the pixelref | |
196 SkOneShotDiscardablePixelRef(const SkImageInfo&, SkDiscardableMemory*, size_ t rowBytes); | |
197 ~SkOneShotDiscardablePixelRef(); | |
198 | |
199 protected: | |
200 virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE; | |
201 virtual void onUnlockPixels() SK_OVERRIDE; | |
202 virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE; | |
203 | |
204 virtual Factory getFactory() const SK_OVERRIDE { return NULL; } | |
hal.canary
2013/12/09 18:23:27
Use SK_DECLARE_UNFLATTENABLE_OBJECT, since that is
reed1
2013/12/09 18:43:48
Done.
| |
205 | |
206 private: | |
207 SkImageInfo fInfo; // remove when SkPixelRef gets this in baseclass | |
208 | |
209 SkDiscardableMemory* fDM; | |
210 size_t fRB; | |
hal.canary
2013/12/09 18:23:27
readability: I'd prefer fRowBytes
reed1
2013/12/09 18:43:48
Will conflict with the SkPixelRef when that CL lan
| |
211 bool fFirstTime; | |
212 | |
213 typedef SkPixelRef INHERITED; | |
214 }; | |
215 | |
216 SkOneShotDiscardablePixelRef::SkOneShotDiscardablePixelRef(const SkImageInfo& in fo, | |
217 SkDiscardableMemory* dm, | |
218 size_t rowBytes) | |
219 : INHERITED(info) | |
220 , fDM(dm) | |
221 , fRB(rowBytes) | |
222 { | |
223 fInfo = info; // remove this redundant field when SkPixelRef has info | |
224 | |
225 SkASSERT(dm->data()); | |
226 fFirstTime = true; | |
227 } | |
228 | |
229 SkOneShotDiscardablePixelRef::~SkOneShotDiscardablePixelRef() { | |
230 SkDELETE(fDM); | |
231 } | |
232 | |
233 void* SkOneShotDiscardablePixelRef::onLockPixels(SkColorTable** ctable) { | |
234 if (fFirstTime) { | |
235 // we're already locked | |
236 fFirstTime = false; | |
237 return fDM->data(); | |
238 } | |
239 return fDM->lock() ? fDM->data() : NULL; | |
240 } | |
241 | |
242 void SkOneShotDiscardablePixelRef::onUnlockPixels() { | |
243 SkASSERT(!fFirstTime); | |
244 fDM->unlock(); | |
245 } | |
246 | |
247 size_t SkOneShotDiscardablePixelRef::getAllocatedSizeInBytes() const { | |
248 return fInfo.fHeight * fRB; | |
249 } | |
250 | |
251 class SkScaledImageCacheDiscardableAllocator : public SkBitmap::Allocator { | |
252 public: | |
253 SkScaledImageCacheDiscardableAllocator( | |
254 SkScaledImageCache::DiscardableFactory factory) { | |
255 fFactory = factory; | |
hal.canary
2013/12/09 18:23:27
Either assert != NULL or explicitly allow NULL (de
reed1
2013/12/09 18:43:48
Defaults are harder to read sometimes, and I don't
| |
256 } | |
257 | |
258 virtual bool allocPixelRef(SkBitmap*, SkColorTable*) SK_OVERRIDE; | |
259 | |
260 private: | |
261 SkScaledImageCache::DiscardableFactory fFactory; | |
262 }; | |
263 | |
264 bool SkScaledImageCacheDiscardableAllocator::allocPixelRef(SkBitmap* bitmap, | |
265 SkColorTable* ctable) { | |
266 size_t size = bitmap->getSize(); | |
267 if (0 == size) { | |
268 return false; | |
269 } | |
270 | |
271 SkDiscardableMemory* dm = fFactory(size); | |
hal.canary
2013/12/09 18:23:27
SkDiscardableMemory* dm;
if (fFactory != NULL)
reed1
2013/12/09 18:43:48
asserting in constructor.
| |
272 if (NULL == dm) { | |
273 return false; | |
274 } | |
275 | |
276 // can relax when we have bitmap::asImageInfo | |
277 if (SkBitmap::kARGB_8888_Config != bitmap->config()) { | |
278 return false; | |
279 } | |
280 | |
281 SkImageInfo info = { | |
282 bitmap->width(), | |
283 bitmap->height(), | |
284 kPMColor_SkColorType, | |
285 bitmap->alphaType() | |
286 }; | |
287 | |
288 bitmap->setPixelRef(SkNEW_ARGS(SkOneShotDiscardablePixelRef, | |
289 (info, dm, bitmap->rowBytes())))->unref(); | |
290 bitmap->lockPixels(); | |
291 return bitmap->readyToDraw(); | |
292 } | |
293 | |
294 SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) { | |
295 this->init(); | |
296 fDiscardableFactory = factory; | |
297 | |
298 fAllocator = SkNEW_ARGS(SkScaledImageCacheDiscardableAllocator, (factory)); | |
299 } | |
300 | |
301 SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { | |
302 this->init(); | |
176 fByteLimit = byteLimit; | 303 fByteLimit = byteLimit; |
177 fCount = 0; | |
178 } | 304 } |
179 | 305 |
180 SkScaledImageCache::~SkScaledImageCache() { | 306 SkScaledImageCache::~SkScaledImageCache() { |
307 SkSafeUnref(fAllocator); | |
308 | |
181 Rec* rec = fHead; | 309 Rec* rec = fHead; |
182 while (rec) { | 310 while (rec) { |
183 Rec* next = rec->fNext; | 311 Rec* next = rec->fNext; |
184 SkDELETE(rec); | 312 SkDELETE(rec); |
185 rec = next; | 313 rec = next; |
186 } | 314 } |
187 delete fHash; | 315 delete fHash; |
188 } | 316 } |
189 | 317 |
190 //////////////////////////////////////////////////////////////////////////////// | 318 //////////////////////////////////////////////////////////////////////////////// |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
360 rec->fLockCount -= 1; | 488 rec->fLockCount -= 1; |
361 | 489 |
362 // we may have been over-budget, but now have released something, so check | 490 // we may have been over-budget, but now have released something, so check |
363 // if we should purge. | 491 // if we should purge. |
364 if (0 == rec->fLockCount) { | 492 if (0 == rec->fLockCount) { |
365 this->purgeAsNeeded(); | 493 this->purgeAsNeeded(); |
366 } | 494 } |
367 } | 495 } |
368 | 496 |
369 void SkScaledImageCache::purgeAsNeeded() { | 497 void SkScaledImageCache::purgeAsNeeded() { |
370 size_t byteLimit = fByteLimit; | 498 size_t byteLimit; |
499 int countLimit; | |
500 | |
501 if (fDiscardableFactory) { | |
502 countLimit = SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT; | |
503 byteLimit = SK_MaxU32; // no limit based on bytes | |
504 } else { | |
505 countLimit = SK_MaxS32; // no limit based on count | |
506 byteLimit = fByteLimit; | |
507 } | |
508 | |
371 size_t bytesUsed = fBytesUsed; | 509 size_t bytesUsed = fBytesUsed; |
372 | 510 int countUsed = fCount; |
511 | |
373 Rec* rec = fTail; | 512 Rec* rec = fTail; |
374 while (rec) { | 513 while (rec) { |
375 if (bytesUsed < byteLimit) { | 514 if (bytesUsed < byteLimit && countUsed < countLimit) { |
376 break; | 515 break; |
377 } | 516 } |
517 | |
378 Rec* prev = rec->fPrev; | 518 Rec* prev = rec->fPrev; |
379 if (0 == rec->fLockCount) { | 519 if (0 == rec->fLockCount) { |
380 size_t used = rec->bytesUsed(); | 520 size_t used = rec->bytesUsed(); |
381 SkASSERT(used <= bytesUsed); | 521 SkASSERT(used <= bytesUsed); |
382 bytesUsed -= used; | |
383 this->detach(rec); | 522 this->detach(rec); |
384 #ifdef USE_HASH | 523 #ifdef USE_HASH |
385 fHash->remove(rec->fKey); | 524 fHash->remove(rec->fKey); |
386 #endif | 525 #endif |
387 | 526 |
388 SkDELETE(rec); | 527 SkDELETE(rec); |
389 fCount -= 1; | 528 |
529 bytesUsed -= used; | |
530 countUsed -= 1; | |
390 } | 531 } |
391 rec = prev; | 532 rec = prev; |
392 } | 533 } |
534 | |
393 fBytesUsed = bytesUsed; | 535 fBytesUsed = bytesUsed; |
536 fCount = countUsed; | |
394 } | 537 } |
395 | 538 |
396 size_t SkScaledImageCache::setByteLimit(size_t newLimit) { | 539 size_t SkScaledImageCache::setByteLimit(size_t newLimit) { |
397 size_t prevLimit = fByteLimit; | 540 size_t prevLimit = fByteLimit; |
398 fByteLimit = newLimit; | 541 fByteLimit = newLimit; |
399 if (newLimit < prevLimit) { | 542 if (newLimit < prevLimit) { |
400 this->purgeAsNeeded(); | 543 this->purgeAsNeeded(); |
401 } | 544 } |
402 return prevLimit; | 545 return prevLimit; |
403 } | 546 } |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
506 } | 649 } |
507 #endif | 650 #endif |
508 | 651 |
509 /////////////////////////////////////////////////////////////////////////////// | 652 /////////////////////////////////////////////////////////////////////////////// |
510 | 653 |
511 #include "SkThread.h" | 654 #include "SkThread.h" |
512 | 655 |
513 SK_DECLARE_STATIC_MUTEX(gMutex); | 656 SK_DECLARE_STATIC_MUTEX(gMutex); |
514 | 657 |
515 static void create_cache(SkScaledImageCache** cache) { | 658 static void create_cache(SkScaledImageCache** cache) { |
659 #ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE | |
660 *cache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory::Create)); | |
661 #else | |
516 *cache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); | 662 *cache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); |
663 #endif | |
517 } | 664 } |
518 | 665 |
519 static SkScaledImageCache* get_cache() { | 666 static SkScaledImageCache* get_cache() { |
520 static SkScaledImageCache* gCache(NULL); | 667 static SkScaledImageCache* gCache(NULL); |
521 SK_DECLARE_STATIC_ONCE(create_cache_once); | 668 SK_DECLARE_STATIC_ONCE(create_cache_once); |
522 SkOnce(&create_cache_once, create_cache, &gCache); | 669 SkOnce(&create_cache_once, create_cache, &gCache); |
523 SkASSERT(NULL != gCache); | 670 SkASSERT(NULL != gCache); |
524 return gCache; | 671 return gCache; |
525 } | 672 } |
526 | 673 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
585 size_t SkScaledImageCache::GetByteLimit() { | 732 size_t SkScaledImageCache::GetByteLimit() { |
586 SkAutoMutexAcquire am(gMutex); | 733 SkAutoMutexAcquire am(gMutex); |
587 return get_cache()->getByteLimit(); | 734 return get_cache()->getByteLimit(); |
588 } | 735 } |
589 | 736 |
590 size_t SkScaledImageCache::SetByteLimit(size_t newLimit) { | 737 size_t SkScaledImageCache::SetByteLimit(size_t newLimit) { |
591 SkAutoMutexAcquire am(gMutex); | 738 SkAutoMutexAcquire am(gMutex); |
592 return get_cache()->setByteLimit(newLimit); | 739 return get_cache()->setByteLimit(newLimit); |
593 } | 740 } |
594 | 741 |
742 SkBitmap::Allocator* SkScaledImageCache::GetAllocator() { | |
743 SkAutoMutexAcquire am(gMutex); | |
744 return get_cache()->allocator(); | |
745 } | |
746 | |
595 /////////////////////////////////////////////////////////////////////////////// | 747 /////////////////////////////////////////////////////////////////////////////// |
596 | 748 |
597 #include "SkGraphics.h" | 749 #include "SkGraphics.h" |
598 | 750 |
599 size_t SkGraphics::GetImageCacheBytesUsed() { | 751 size_t SkGraphics::GetImageCacheBytesUsed() { |
600 return SkScaledImageCache::GetBytesUsed(); | 752 return SkScaledImageCache::GetBytesUsed(); |
601 } | 753 } |
602 | 754 |
603 size_t SkGraphics::GetImageCacheByteLimit() { | 755 size_t SkGraphics::GetImageCacheByteLimit() { |
604 return SkScaledImageCache::GetByteLimit(); | 756 return SkScaledImageCache::GetByteLimit(); |
605 } | 757 } |
606 | 758 |
607 size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { | 759 size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { |
608 return SkScaledImageCache::SetByteLimit(newLimit); | 760 return SkScaledImageCache::SetByteLimit(newLimit); |
609 } | 761 } |
OLD | NEW |