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 |
| 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 SK_DECLARE_UNFLATTENABLE_OBJECT() |
| 200 |
| 201 protected: |
| 202 virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE; |
| 203 virtual void onUnlockPixels() SK_OVERRIDE; |
| 204 virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE; |
| 205 |
| 206 private: |
| 207 SkImageInfo fInfo; // remove when SkPixelRef gets this in baseclass |
| 208 |
| 209 SkDiscardableMemory* fDM; |
| 210 size_t fRB; |
| 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 SkASSERT(factory); |
| 256 fFactory = factory; |
| 257 } |
| 258 |
| 259 virtual bool allocPixelRef(SkBitmap*, SkColorTable*) SK_OVERRIDE; |
| 260 |
| 261 private: |
| 262 SkScaledImageCache::DiscardableFactory fFactory; |
| 263 }; |
| 264 |
| 265 bool SkScaledImageCacheDiscardableAllocator::allocPixelRef(SkBitmap* bitmap, |
| 266 SkColorTable* ctable) { |
| 267 size_t size = bitmap->getSize(); |
| 268 if (0 == size) { |
| 269 return false; |
| 270 } |
| 271 |
| 272 SkDiscardableMemory* dm = fFactory(size); |
| 273 if (NULL == dm) { |
| 274 return false; |
| 275 } |
| 276 |
| 277 // can relax when we have bitmap::asImageInfo |
| 278 if (SkBitmap::kARGB_8888_Config != bitmap->config()) { |
| 279 return false; |
| 280 } |
| 281 |
| 282 SkImageInfo info = { |
| 283 bitmap->width(), |
| 284 bitmap->height(), |
| 285 kPMColor_SkColorType, |
| 286 bitmap->alphaType() |
| 287 }; |
| 288 |
| 289 bitmap->setPixelRef(SkNEW_ARGS(SkOneShotDiscardablePixelRef, |
| 290 (info, dm, bitmap->rowBytes())))->unref(); |
| 291 bitmap->lockPixels(); |
| 292 return bitmap->readyToDraw(); |
| 293 } |
| 294 |
| 295 SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) { |
| 296 this->init(); |
| 297 fDiscardableFactory = factory; |
| 298 |
| 299 fAllocator = SkNEW_ARGS(SkScaledImageCacheDiscardableAllocator, (factory)); |
| 300 } |
| 301 |
| 302 SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { |
| 303 this->init(); |
176 fByteLimit = byteLimit; | 304 fByteLimit = byteLimit; |
177 fCount = 0; | |
178 } | 305 } |
179 | 306 |
180 SkScaledImageCache::~SkScaledImageCache() { | 307 SkScaledImageCache::~SkScaledImageCache() { |
| 308 SkSafeUnref(fAllocator); |
| 309 |
181 Rec* rec = fHead; | 310 Rec* rec = fHead; |
182 while (rec) { | 311 while (rec) { |
183 Rec* next = rec->fNext; | 312 Rec* next = rec->fNext; |
184 SkDELETE(rec); | 313 SkDELETE(rec); |
185 rec = next; | 314 rec = next; |
186 } | 315 } |
187 delete fHash; | 316 delete fHash; |
188 } | 317 } |
189 | 318 |
190 //////////////////////////////////////////////////////////////////////////////// | 319 //////////////////////////////////////////////////////////////////////////////// |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 rec->fLockCount -= 1; | 489 rec->fLockCount -= 1; |
361 | 490 |
362 // we may have been over-budget, but now have released something, so check | 491 // we may have been over-budget, but now have released something, so check |
363 // if we should purge. | 492 // if we should purge. |
364 if (0 == rec->fLockCount) { | 493 if (0 == rec->fLockCount) { |
365 this->purgeAsNeeded(); | 494 this->purgeAsNeeded(); |
366 } | 495 } |
367 } | 496 } |
368 | 497 |
369 void SkScaledImageCache::purgeAsNeeded() { | 498 void SkScaledImageCache::purgeAsNeeded() { |
370 size_t byteLimit = fByteLimit; | 499 size_t byteLimit; |
| 500 int countLimit; |
| 501 |
| 502 if (fDiscardableFactory) { |
| 503 countLimit = SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT; |
| 504 byteLimit = SK_MaxU32; // no limit based on bytes |
| 505 } else { |
| 506 countLimit = SK_MaxS32; // no limit based on count |
| 507 byteLimit = fByteLimit; |
| 508 } |
| 509 |
371 size_t bytesUsed = fBytesUsed; | 510 size_t bytesUsed = fBytesUsed; |
372 | 511 int countUsed = fCount; |
| 512 |
373 Rec* rec = fTail; | 513 Rec* rec = fTail; |
374 while (rec) { | 514 while (rec) { |
375 if (bytesUsed < byteLimit) { | 515 if (bytesUsed < byteLimit && countUsed < countLimit) { |
376 break; | 516 break; |
377 } | 517 } |
| 518 |
378 Rec* prev = rec->fPrev; | 519 Rec* prev = rec->fPrev; |
379 if (0 == rec->fLockCount) { | 520 if (0 == rec->fLockCount) { |
380 size_t used = rec->bytesUsed(); | 521 size_t used = rec->bytesUsed(); |
381 SkASSERT(used <= bytesUsed); | 522 SkASSERT(used <= bytesUsed); |
382 bytesUsed -= used; | |
383 this->detach(rec); | 523 this->detach(rec); |
384 #ifdef USE_HASH | 524 #ifdef USE_HASH |
385 fHash->remove(rec->fKey); | 525 fHash->remove(rec->fKey); |
386 #endif | 526 #endif |
387 | 527 |
388 SkDELETE(rec); | 528 SkDELETE(rec); |
389 fCount -= 1; | 529 |
| 530 bytesUsed -= used; |
| 531 countUsed -= 1; |
390 } | 532 } |
391 rec = prev; | 533 rec = prev; |
392 } | 534 } |
| 535 |
393 fBytesUsed = bytesUsed; | 536 fBytesUsed = bytesUsed; |
| 537 fCount = countUsed; |
394 } | 538 } |
395 | 539 |
396 size_t SkScaledImageCache::setByteLimit(size_t newLimit) { | 540 size_t SkScaledImageCache::setByteLimit(size_t newLimit) { |
397 size_t prevLimit = fByteLimit; | 541 size_t prevLimit = fByteLimit; |
398 fByteLimit = newLimit; | 542 fByteLimit = newLimit; |
399 if (newLimit < prevLimit) { | 543 if (newLimit < prevLimit) { |
400 this->purgeAsNeeded(); | 544 this->purgeAsNeeded(); |
401 } | 545 } |
402 return prevLimit; | 546 return prevLimit; |
403 } | 547 } |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 } | 650 } |
507 #endif | 651 #endif |
508 | 652 |
509 /////////////////////////////////////////////////////////////////////////////// | 653 /////////////////////////////////////////////////////////////////////////////// |
510 | 654 |
511 #include "SkThread.h" | 655 #include "SkThread.h" |
512 | 656 |
513 SK_DECLARE_STATIC_MUTEX(gMutex); | 657 SK_DECLARE_STATIC_MUTEX(gMutex); |
514 | 658 |
515 static void create_cache(SkScaledImageCache** cache) { | 659 static void create_cache(SkScaledImageCache** cache) { |
| 660 #ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE |
| 661 *cache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory::Create)); |
| 662 #else |
516 *cache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); | 663 *cache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); |
| 664 #endif |
517 } | 665 } |
518 | 666 |
519 static SkScaledImageCache* get_cache() { | 667 static SkScaledImageCache* get_cache() { |
520 static SkScaledImageCache* gCache(NULL); | 668 static SkScaledImageCache* gCache(NULL); |
521 SK_DECLARE_STATIC_ONCE(create_cache_once); | 669 SK_DECLARE_STATIC_ONCE(create_cache_once); |
522 SkOnce(&create_cache_once, create_cache, &gCache); | 670 SkOnce(&create_cache_once, create_cache, &gCache); |
523 SkASSERT(NULL != gCache); | 671 SkASSERT(NULL != gCache); |
524 return gCache; | 672 return gCache; |
525 } | 673 } |
526 | 674 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 size_t SkScaledImageCache::GetByteLimit() { | 733 size_t SkScaledImageCache::GetByteLimit() { |
586 SkAutoMutexAcquire am(gMutex); | 734 SkAutoMutexAcquire am(gMutex); |
587 return get_cache()->getByteLimit(); | 735 return get_cache()->getByteLimit(); |
588 } | 736 } |
589 | 737 |
590 size_t SkScaledImageCache::SetByteLimit(size_t newLimit) { | 738 size_t SkScaledImageCache::SetByteLimit(size_t newLimit) { |
591 SkAutoMutexAcquire am(gMutex); | 739 SkAutoMutexAcquire am(gMutex); |
592 return get_cache()->setByteLimit(newLimit); | 740 return get_cache()->setByteLimit(newLimit); |
593 } | 741 } |
594 | 742 |
| 743 SkBitmap::Allocator* SkScaledImageCache::GetAllocator() { |
| 744 SkAutoMutexAcquire am(gMutex); |
| 745 return get_cache()->allocator(); |
| 746 } |
| 747 |
595 /////////////////////////////////////////////////////////////////////////////// | 748 /////////////////////////////////////////////////////////////////////////////// |
596 | 749 |
597 #include "SkGraphics.h" | 750 #include "SkGraphics.h" |
598 | 751 |
599 size_t SkGraphics::GetImageCacheBytesUsed() { | 752 size_t SkGraphics::GetImageCacheBytesUsed() { |
600 return SkScaledImageCache::GetBytesUsed(); | 753 return SkScaledImageCache::GetBytesUsed(); |
601 } | 754 } |
602 | 755 |
603 size_t SkGraphics::GetImageCacheByteLimit() { | 756 size_t SkGraphics::GetImageCacheByteLimit() { |
604 return SkScaledImageCache::GetByteLimit(); | 757 return SkScaledImageCache::GetByteLimit(); |
605 } | 758 } |
606 | 759 |
607 size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { | 760 size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { |
608 return SkScaledImageCache::SetByteLimit(newLimit); | 761 return SkScaledImageCache::SetByteLimit(newLimit); |
609 } | 762 } |
OLD | NEW |