Chromium Code Reviews| 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 |