1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkScaledImageCache.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,798 @@ 1.4 +/* 1.5 + * Copyright 2013 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkScaledImageCache.h" 1.12 +#include "SkMipMap.h" 1.13 +#include "SkOnce.h" 1.14 +#include "SkPixelRef.h" 1.15 +#include "SkRect.h" 1.16 + 1.17 +// This can be defined by the caller's build system 1.18 +//#define SK_USE_DISCARDABLE_SCALEDIMAGECACHE 1.19 + 1.20 +#ifndef SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT 1.21 +# define SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT 1024 1.22 +#endif 1.23 + 1.24 +#ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT 1.25 + #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) 1.26 +#endif 1.27 + 1.28 +static inline SkScaledImageCache::ID* rec_to_id(SkScaledImageCache::Rec* rec) { 1.29 + return reinterpret_cast<SkScaledImageCache::ID*>(rec); 1.30 +} 1.31 + 1.32 +static inline SkScaledImageCache::Rec* id_to_rec(SkScaledImageCache::ID* id) { 1.33 + return reinterpret_cast<SkScaledImageCache::Rec*>(id); 1.34 +} 1.35 + 1.36 + // Implemented from en.wikipedia.org/wiki/MurmurHash. 1.37 +static uint32_t compute_hash(const uint32_t data[], int count) { 1.38 + uint32_t hash = 0; 1.39 + 1.40 + for (int i = 0; i < count; ++i) { 1.41 + uint32_t k = data[i]; 1.42 + k *= 0xcc9e2d51; 1.43 + k = (k << 15) | (k >> 17); 1.44 + k *= 0x1b873593; 1.45 + 1.46 + hash ^= k; 1.47 + hash = (hash << 13) | (hash >> 19); 1.48 + hash *= 5; 1.49 + hash += 0xe6546b64; 1.50 + } 1.51 + 1.52 + // hash ^= size; 1.53 + hash ^= hash >> 16; 1.54 + hash *= 0x85ebca6b; 1.55 + hash ^= hash >> 13; 1.56 + hash *= 0xc2b2ae35; 1.57 + hash ^= hash >> 16; 1.58 + 1.59 + return hash; 1.60 +} 1.61 + 1.62 +struct SkScaledImageCache::Key { 1.63 + Key(uint32_t genID, 1.64 + SkScalar scaleX, 1.65 + SkScalar scaleY, 1.66 + SkIRect bounds) 1.67 + : fGenID(genID) 1.68 + , fScaleX(scaleX) 1.69 + , fScaleY(scaleY) 1.70 + , fBounds(bounds) { 1.71 + fHash = compute_hash(&fGenID, 7); 1.72 + } 1.73 + 1.74 + bool operator<(const Key& other) const { 1.75 + const uint32_t* a = &fGenID; 1.76 + const uint32_t* b = &other.fGenID; 1.77 + for (int i = 0; i < 7; ++i) { 1.78 + if (a[i] < b[i]) { 1.79 + return true; 1.80 + } 1.81 + if (a[i] > b[i]) { 1.82 + return false; 1.83 + } 1.84 + } 1.85 + return false; 1.86 + } 1.87 + 1.88 + bool operator==(const Key& other) const { 1.89 + const uint32_t* a = &fHash; 1.90 + const uint32_t* b = &other.fHash; 1.91 + for (int i = 0; i < 8; ++i) { 1.92 + if (a[i] != b[i]) { 1.93 + return false; 1.94 + } 1.95 + } 1.96 + return true; 1.97 + } 1.98 + 1.99 + uint32_t fHash; 1.100 + uint32_t fGenID; 1.101 + float fScaleX; 1.102 + float fScaleY; 1.103 + SkIRect fBounds; 1.104 +}; 1.105 + 1.106 +struct SkScaledImageCache::Rec { 1.107 + Rec(const Key& key, const SkBitmap& bm) : fKey(key), fBitmap(bm) { 1.108 + fLockCount = 1; 1.109 + fMip = NULL; 1.110 + } 1.111 + 1.112 + Rec(const Key& key, const SkMipMap* mip) : fKey(key) { 1.113 + fLockCount = 1; 1.114 + fMip = mip; 1.115 + mip->ref(); 1.116 + } 1.117 + 1.118 + ~Rec() { 1.119 + SkSafeUnref(fMip); 1.120 + } 1.121 + 1.122 + size_t bytesUsed() const { 1.123 + return fMip ? fMip->getSize() : fBitmap.getSize(); 1.124 + } 1.125 + 1.126 + Rec* fNext; 1.127 + Rec* fPrev; 1.128 + 1.129 + // this guy wants to be 64bit aligned 1.130 + Key fKey; 1.131 + 1.132 + int32_t fLockCount; 1.133 + 1.134 + // we use either fBitmap or fMip, but not both 1.135 + SkBitmap fBitmap; 1.136 + const SkMipMap* fMip; 1.137 +}; 1.138 + 1.139 +#include "SkTDynamicHash.h" 1.140 + 1.141 +namespace { // can't use static functions w/ template parameters 1.142 +const SkScaledImageCache::Key& key_from_rec(const SkScaledImageCache::Rec& rec) { 1.143 + return rec.fKey; 1.144 +} 1.145 + 1.146 +uint32_t hash_from_key(const SkScaledImageCache::Key& key) { 1.147 + return key.fHash; 1.148 +} 1.149 + 1.150 +bool eq_rec_key(const SkScaledImageCache::Rec& rec, const SkScaledImageCache::Key& key) { 1.151 + return rec.fKey == key; 1.152 +} 1.153 +} 1.154 + 1.155 +class SkScaledImageCache::Hash : public SkTDynamicHash<SkScaledImageCache::Rec, 1.156 + SkScaledImageCache::Key, 1.157 + key_from_rec, 1.158 + hash_from_key, 1.159 + eq_rec_key> {}; 1.160 + 1.161 +/////////////////////////////////////////////////////////////////////////////// 1.162 + 1.163 +// experimental hash to speed things up 1.164 +#define USE_HASH 1.165 + 1.166 +#if !defined(USE_HASH) 1.167 +static inline SkScaledImageCache::Rec* find_rec_in_list( 1.168 + SkScaledImageCache::Rec* head, const Key & key) { 1.169 + SkScaledImageCache::Rec* rec = head; 1.170 + while ((rec != NULL) && (rec->fKey != key)) { 1.171 + rec = rec->fNext; 1.172 + } 1.173 + return rec; 1.174 +} 1.175 +#endif 1.176 + 1.177 +void SkScaledImageCache::init() { 1.178 + fHead = NULL; 1.179 + fTail = NULL; 1.180 +#ifdef USE_HASH 1.181 + fHash = new Hash; 1.182 +#else 1.183 + fHash = NULL; 1.184 +#endif 1.185 + fBytesUsed = 0; 1.186 + fCount = 0; 1.187 + fAllocator = NULL; 1.188 + 1.189 + // One of these should be explicit set by the caller after we return. 1.190 + fByteLimit = 0; 1.191 + fDiscardableFactory = NULL; 1.192 +} 1.193 + 1.194 +#include "SkDiscardableMemory.h" 1.195 + 1.196 +class SkOneShotDiscardablePixelRef : public SkPixelRef { 1.197 +public: 1.198 + SK_DECLARE_INST_COUNT(SkOneShotDiscardablePixelRef) 1.199 + // Ownership of the discardablememory is transfered to the pixelref 1.200 + SkOneShotDiscardablePixelRef(const SkImageInfo&, SkDiscardableMemory*, size_t rowBytes); 1.201 + ~SkOneShotDiscardablePixelRef(); 1.202 + 1.203 + SK_DECLARE_UNFLATTENABLE_OBJECT() 1.204 + 1.205 +protected: 1.206 + virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE; 1.207 + virtual void onUnlockPixels() SK_OVERRIDE; 1.208 + virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE; 1.209 + 1.210 +private: 1.211 + SkDiscardableMemory* fDM; 1.212 + size_t fRB; 1.213 + bool fFirstTime; 1.214 + 1.215 + typedef SkPixelRef INHERITED; 1.216 +}; 1.217 + 1.218 +SkOneShotDiscardablePixelRef::SkOneShotDiscardablePixelRef(const SkImageInfo& info, 1.219 + SkDiscardableMemory* dm, 1.220 + size_t rowBytes) 1.221 + : INHERITED(info) 1.222 + , fDM(dm) 1.223 + , fRB(rowBytes) 1.224 +{ 1.225 + SkASSERT(dm->data()); 1.226 + fFirstTime = true; 1.227 +} 1.228 + 1.229 +SkOneShotDiscardablePixelRef::~SkOneShotDiscardablePixelRef() { 1.230 + SkDELETE(fDM); 1.231 +} 1.232 + 1.233 +bool SkOneShotDiscardablePixelRef::onNewLockPixels(LockRec* rec) { 1.234 + if (fFirstTime) { 1.235 + // we're already locked 1.236 + SkASSERT(fDM->data()); 1.237 + fFirstTime = false; 1.238 + goto SUCCESS; 1.239 + } 1.240 + 1.241 + // A previous call to onUnlock may have deleted our DM, so check for that 1.242 + if (NULL == fDM) { 1.243 + return false; 1.244 + } 1.245 + 1.246 + if (!fDM->lock()) { 1.247 + // since it failed, we delete it now, to free-up the resource 1.248 + delete fDM; 1.249 + fDM = NULL; 1.250 + return false; 1.251 + } 1.252 + 1.253 +SUCCESS: 1.254 + rec->fPixels = fDM->data(); 1.255 + rec->fColorTable = NULL; 1.256 + rec->fRowBytes = fRB; 1.257 + return true; 1.258 +} 1.259 + 1.260 +void SkOneShotDiscardablePixelRef::onUnlockPixels() { 1.261 + SkASSERT(!fFirstTime); 1.262 + fDM->unlock(); 1.263 +} 1.264 + 1.265 +size_t SkOneShotDiscardablePixelRef::getAllocatedSizeInBytes() const { 1.266 + return this->info().getSafeSize(fRB); 1.267 +} 1.268 + 1.269 +class SkScaledImageCacheDiscardableAllocator : public SkBitmap::Allocator { 1.270 +public: 1.271 + SkScaledImageCacheDiscardableAllocator( 1.272 + SkScaledImageCache::DiscardableFactory factory) { 1.273 + SkASSERT(factory); 1.274 + fFactory = factory; 1.275 + } 1.276 + 1.277 + virtual bool allocPixelRef(SkBitmap*, SkColorTable*) SK_OVERRIDE; 1.278 + 1.279 +private: 1.280 + SkScaledImageCache::DiscardableFactory fFactory; 1.281 +}; 1.282 + 1.283 +bool SkScaledImageCacheDiscardableAllocator::allocPixelRef(SkBitmap* bitmap, 1.284 + SkColorTable* ctable) { 1.285 + size_t size = bitmap->getSize(); 1.286 + if (0 == size) { 1.287 + return false; 1.288 + } 1.289 + 1.290 + SkDiscardableMemory* dm = fFactory(size); 1.291 + if (NULL == dm) { 1.292 + return false; 1.293 + } 1.294 + 1.295 + // can we relax this? 1.296 + if (kPMColor_SkColorType != bitmap->colorType()) { 1.297 + return false; 1.298 + } 1.299 + 1.300 + SkImageInfo info = bitmap->info(); 1.301 + bitmap->setPixelRef(SkNEW_ARGS(SkOneShotDiscardablePixelRef, 1.302 + (info, dm, bitmap->rowBytes())))->unref(); 1.303 + bitmap->lockPixels(); 1.304 + return bitmap->readyToDraw(); 1.305 +} 1.306 + 1.307 +SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) { 1.308 + this->init(); 1.309 + fDiscardableFactory = factory; 1.310 + 1.311 + fAllocator = SkNEW_ARGS(SkScaledImageCacheDiscardableAllocator, (factory)); 1.312 +} 1.313 + 1.314 +SkScaledImageCache::SkScaledImageCache(size_t byteLimit) { 1.315 + this->init(); 1.316 + fByteLimit = byteLimit; 1.317 +} 1.318 + 1.319 +SkScaledImageCache::~SkScaledImageCache() { 1.320 + SkSafeUnref(fAllocator); 1.321 + 1.322 + Rec* rec = fHead; 1.323 + while (rec) { 1.324 + Rec* next = rec->fNext; 1.325 + SkDELETE(rec); 1.326 + rec = next; 1.327 + } 1.328 + delete fHash; 1.329 +} 1.330 + 1.331 +//////////////////////////////////////////////////////////////////////////////// 1.332 + 1.333 + 1.334 +SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(uint32_t genID, 1.335 + SkScalar scaleX, 1.336 + SkScalar scaleY, 1.337 + const SkIRect& bounds) { 1.338 + const Key key(genID, scaleX, scaleY, bounds); 1.339 + return this->findAndLock(key); 1.340 +} 1.341 + 1.342 +/** 1.343 + This private method is the fully general record finder. All other 1.344 + record finders should call this function or the one above. */ 1.345 +SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkScaledImageCache::Key& key) { 1.346 + if (key.fBounds.isEmpty()) { 1.347 + return NULL; 1.348 + } 1.349 +#ifdef USE_HASH 1.350 + Rec* rec = fHash->find(key); 1.351 +#else 1.352 + Rec* rec = find_rec_in_list(fHead, key); 1.353 +#endif 1.354 + if (rec) { 1.355 + this->moveToHead(rec); // for our LRU 1.356 + rec->fLockCount += 1; 1.357 + } 1.358 + return rec; 1.359 +} 1.360 + 1.361 +/** 1.362 + This function finds the bounds of the bitmap *within its pixelRef*. 1.363 + If the bitmap lacks a pixelRef, it will return an empty rect, since 1.364 + that doesn't make sense. This may be a useful enough function that 1.365 + it should be somewhere else (in SkBitmap?). */ 1.366 +static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) { 1.367 + if (!(bm.pixelRef())) { 1.368 + return SkIRect::MakeEmpty(); 1.369 + } 1.370 + SkIPoint origin = bm.pixelRefOrigin(); 1.371 + return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height()); 1.372 +} 1.373 + 1.374 + 1.375 +SkScaledImageCache::ID* SkScaledImageCache::findAndLock(uint32_t genID, 1.376 + int32_t width, 1.377 + int32_t height, 1.378 + SkBitmap* bitmap) { 1.379 + Rec* rec = this->findAndLock(genID, SK_Scalar1, SK_Scalar1, 1.380 + SkIRect::MakeWH(width, height)); 1.381 + if (rec) { 1.382 + SkASSERT(NULL == rec->fMip); 1.383 + SkASSERT(rec->fBitmap.pixelRef()); 1.384 + *bitmap = rec->fBitmap; 1.385 + } 1.386 + return rec_to_id(rec); 1.387 +} 1.388 + 1.389 +SkScaledImageCache::ID* SkScaledImageCache::findAndLock(const SkBitmap& orig, 1.390 + SkScalar scaleX, 1.391 + SkScalar scaleY, 1.392 + SkBitmap* scaled) { 1.393 + if (0 == scaleX || 0 == scaleY) { 1.394 + // degenerate, and the key we use for mipmaps 1.395 + return NULL; 1.396 + } 1.397 + Rec* rec = this->findAndLock(orig.getGenerationID(), scaleX, 1.398 + scaleY, get_bounds_from_bitmap(orig)); 1.399 + if (rec) { 1.400 + SkASSERT(NULL == rec->fMip); 1.401 + SkASSERT(rec->fBitmap.pixelRef()); 1.402 + *scaled = rec->fBitmap; 1.403 + } 1.404 + return rec_to_id(rec); 1.405 +} 1.406 + 1.407 +SkScaledImageCache::ID* SkScaledImageCache::findAndLockMip(const SkBitmap& orig, 1.408 + SkMipMap const ** mip) { 1.409 + Rec* rec = this->findAndLock(orig.getGenerationID(), 0, 0, 1.410 + get_bounds_from_bitmap(orig)); 1.411 + if (rec) { 1.412 + SkASSERT(rec->fMip); 1.413 + SkASSERT(NULL == rec->fBitmap.pixelRef()); 1.414 + *mip = rec->fMip; 1.415 + } 1.416 + return rec_to_id(rec); 1.417 +} 1.418 + 1.419 + 1.420 +//////////////////////////////////////////////////////////////////////////////// 1.421 +/** 1.422 + This private method is the fully general record adder. All other 1.423 + record adders should call this funtion. */ 1.424 +SkScaledImageCache::ID* SkScaledImageCache::addAndLock(SkScaledImageCache::Rec* rec) { 1.425 + SkASSERT(rec); 1.426 + // See if we already have this key (racy inserts, etc.) 1.427 + Rec* existing = this->findAndLock(rec->fKey); 1.428 + if (NULL != existing) { 1.429 + // Since we already have a matching entry, just delete the new one and return. 1.430 + // Call sites cannot assume the passed in object will live past this call. 1.431 + existing->fBitmap = rec->fBitmap; 1.432 + SkDELETE(rec); 1.433 + return rec_to_id(existing); 1.434 + } 1.435 + 1.436 + this->addToHead(rec); 1.437 + SkASSERT(1 == rec->fLockCount); 1.438 +#ifdef USE_HASH 1.439 + SkASSERT(fHash); 1.440 + fHash->add(rec); 1.441 +#endif 1.442 + // We may (now) be overbudget, so see if we need to purge something. 1.443 + this->purgeAsNeeded(); 1.444 + return rec_to_id(rec); 1.445 +} 1.446 + 1.447 +SkScaledImageCache::ID* SkScaledImageCache::addAndLock(uint32_t genID, 1.448 + int32_t width, 1.449 + int32_t height, 1.450 + const SkBitmap& bitmap) { 1.451 + Key key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeWH(width, height)); 1.452 + Rec* rec = SkNEW_ARGS(Rec, (key, bitmap)); 1.453 + return this->addAndLock(rec); 1.454 +} 1.455 + 1.456 +SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig, 1.457 + SkScalar scaleX, 1.458 + SkScalar scaleY, 1.459 + const SkBitmap& scaled) { 1.460 + if (0 == scaleX || 0 == scaleY) { 1.461 + // degenerate, and the key we use for mipmaps 1.462 + return NULL; 1.463 + } 1.464 + SkIRect bounds = get_bounds_from_bitmap(orig); 1.465 + if (bounds.isEmpty()) { 1.466 + return NULL; 1.467 + } 1.468 + Key key(orig.getGenerationID(), scaleX, scaleY, bounds); 1.469 + Rec* rec = SkNEW_ARGS(Rec, (key, scaled)); 1.470 + return this->addAndLock(rec); 1.471 +} 1.472 + 1.473 +SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig, 1.474 + const SkMipMap* mip) { 1.475 + SkIRect bounds = get_bounds_from_bitmap(orig); 1.476 + if (bounds.isEmpty()) { 1.477 + return NULL; 1.478 + } 1.479 + Key key(orig.getGenerationID(), 0, 0, bounds); 1.480 + Rec* rec = SkNEW_ARGS(Rec, (key, mip)); 1.481 + return this->addAndLock(rec); 1.482 +} 1.483 + 1.484 +void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) { 1.485 + SkASSERT(id); 1.486 + 1.487 +#ifdef SK_DEBUG 1.488 + { 1.489 + bool found = false; 1.490 + Rec* rec = fHead; 1.491 + while (rec != NULL) { 1.492 + if (rec == id_to_rec(id)) { 1.493 + found = true; 1.494 + break; 1.495 + } 1.496 + rec = rec->fNext; 1.497 + } 1.498 + SkASSERT(found); 1.499 + } 1.500 +#endif 1.501 + Rec* rec = id_to_rec(id); 1.502 + SkASSERT(rec->fLockCount > 0); 1.503 + rec->fLockCount -= 1; 1.504 + 1.505 + // we may have been over-budget, but now have released something, so check 1.506 + // if we should purge. 1.507 + if (0 == rec->fLockCount) { 1.508 + this->purgeAsNeeded(); 1.509 + } 1.510 +} 1.511 + 1.512 +void SkScaledImageCache::purgeAsNeeded() { 1.513 + size_t byteLimit; 1.514 + int countLimit; 1.515 + 1.516 + if (fDiscardableFactory) { 1.517 + countLimit = SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT; 1.518 + byteLimit = SK_MaxU32; // no limit based on bytes 1.519 + } else { 1.520 + countLimit = SK_MaxS32; // no limit based on count 1.521 + byteLimit = fByteLimit; 1.522 + } 1.523 + 1.524 + size_t bytesUsed = fBytesUsed; 1.525 + int countUsed = fCount; 1.526 + 1.527 + Rec* rec = fTail; 1.528 + while (rec) { 1.529 + if (bytesUsed < byteLimit && countUsed < countLimit) { 1.530 + break; 1.531 + } 1.532 + 1.533 + Rec* prev = rec->fPrev; 1.534 + if (0 == rec->fLockCount) { 1.535 + size_t used = rec->bytesUsed(); 1.536 + SkASSERT(used <= bytesUsed); 1.537 + this->detach(rec); 1.538 +#ifdef USE_HASH 1.539 + fHash->remove(rec->fKey); 1.540 +#endif 1.541 + 1.542 + SkDELETE(rec); 1.543 + 1.544 + bytesUsed -= used; 1.545 + countUsed -= 1; 1.546 + } 1.547 + rec = prev; 1.548 + } 1.549 + 1.550 + fBytesUsed = bytesUsed; 1.551 + fCount = countUsed; 1.552 +} 1.553 + 1.554 +size_t SkScaledImageCache::setByteLimit(size_t newLimit) { 1.555 + size_t prevLimit = fByteLimit; 1.556 + fByteLimit = newLimit; 1.557 + if (newLimit < prevLimit) { 1.558 + this->purgeAsNeeded(); 1.559 + } 1.560 + return prevLimit; 1.561 +} 1.562 + 1.563 +/////////////////////////////////////////////////////////////////////////////// 1.564 + 1.565 +void SkScaledImageCache::detach(Rec* rec) { 1.566 + Rec* prev = rec->fPrev; 1.567 + Rec* next = rec->fNext; 1.568 + 1.569 + if (!prev) { 1.570 + SkASSERT(fHead == rec); 1.571 + fHead = next; 1.572 + } else { 1.573 + prev->fNext = next; 1.574 + } 1.575 + 1.576 + if (!next) { 1.577 + fTail = prev; 1.578 + } else { 1.579 + next->fPrev = prev; 1.580 + } 1.581 + 1.582 + rec->fNext = rec->fPrev = NULL; 1.583 +} 1.584 + 1.585 +void SkScaledImageCache::moveToHead(Rec* rec) { 1.586 + if (fHead == rec) { 1.587 + return; 1.588 + } 1.589 + 1.590 + SkASSERT(fHead); 1.591 + SkASSERT(fTail); 1.592 + 1.593 + this->validate(); 1.594 + 1.595 + this->detach(rec); 1.596 + 1.597 + fHead->fPrev = rec; 1.598 + rec->fNext = fHead; 1.599 + fHead = rec; 1.600 + 1.601 + this->validate(); 1.602 +} 1.603 + 1.604 +void SkScaledImageCache::addToHead(Rec* rec) { 1.605 + this->validate(); 1.606 + 1.607 + rec->fPrev = NULL; 1.608 + rec->fNext = fHead; 1.609 + if (fHead) { 1.610 + fHead->fPrev = rec; 1.611 + } 1.612 + fHead = rec; 1.613 + if (!fTail) { 1.614 + fTail = rec; 1.615 + } 1.616 + fBytesUsed += rec->bytesUsed(); 1.617 + fCount += 1; 1.618 + 1.619 + this->validate(); 1.620 +} 1.621 + 1.622 +/////////////////////////////////////////////////////////////////////////////// 1.623 + 1.624 +#ifdef SK_DEBUG 1.625 +void SkScaledImageCache::validate() const { 1.626 + if (NULL == fHead) { 1.627 + SkASSERT(NULL == fTail); 1.628 + SkASSERT(0 == fBytesUsed); 1.629 + return; 1.630 + } 1.631 + 1.632 + if (fHead == fTail) { 1.633 + SkASSERT(NULL == fHead->fPrev); 1.634 + SkASSERT(NULL == fHead->fNext); 1.635 + SkASSERT(fHead->bytesUsed() == fBytesUsed); 1.636 + return; 1.637 + } 1.638 + 1.639 + SkASSERT(NULL == fHead->fPrev); 1.640 + SkASSERT(NULL != fHead->fNext); 1.641 + SkASSERT(NULL == fTail->fNext); 1.642 + SkASSERT(NULL != fTail->fPrev); 1.643 + 1.644 + size_t used = 0; 1.645 + int count = 0; 1.646 + const Rec* rec = fHead; 1.647 + while (rec) { 1.648 + count += 1; 1.649 + used += rec->bytesUsed(); 1.650 + SkASSERT(used <= fBytesUsed); 1.651 + rec = rec->fNext; 1.652 + } 1.653 + SkASSERT(fCount == count); 1.654 + 1.655 + rec = fTail; 1.656 + while (rec) { 1.657 + SkASSERT(count > 0); 1.658 + count -= 1; 1.659 + SkASSERT(used >= rec->bytesUsed()); 1.660 + used -= rec->bytesUsed(); 1.661 + rec = rec->fPrev; 1.662 + } 1.663 + 1.664 + SkASSERT(0 == count); 1.665 + SkASSERT(0 == used); 1.666 +} 1.667 +#endif 1.668 + 1.669 +void SkScaledImageCache::dump() const { 1.670 + this->validate(); 1.671 + 1.672 + const Rec* rec = fHead; 1.673 + int locked = 0; 1.674 + while (rec) { 1.675 + locked += rec->fLockCount > 0; 1.676 + rec = rec->fNext; 1.677 + } 1.678 + 1.679 + SkDebugf("SkScaledImageCache: count=%d bytes=%d locked=%d %s\n", 1.680 + fCount, fBytesUsed, locked, 1.681 + fDiscardableFactory ? "discardable" : "malloc"); 1.682 +} 1.683 + 1.684 +/////////////////////////////////////////////////////////////////////////////// 1.685 + 1.686 +#include "SkThread.h" 1.687 + 1.688 +SK_DECLARE_STATIC_MUTEX(gMutex); 1.689 +static SkScaledImageCache* gScaledImageCache = NULL; 1.690 +static void cleanup_gScaledImageCache() { SkDELETE(gScaledImageCache); } 1.691 + 1.692 +static void create_cache(int) { 1.693 +#ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE 1.694 + gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory::Create)); 1.695 +#else 1.696 + gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT)); 1.697 +#endif 1.698 +} 1.699 + 1.700 +static SkScaledImageCache* get_cache() { 1.701 + SK_DECLARE_STATIC_ONCE(once); 1.702 + SkOnce(&once, create_cache, 0, cleanup_gScaledImageCache); 1.703 + SkASSERT(NULL != gScaledImageCache); 1.704 + return gScaledImageCache; 1.705 +} 1.706 + 1.707 + 1.708 +SkScaledImageCache::ID* SkScaledImageCache::FindAndLock( 1.709 + uint32_t pixelGenerationID, 1.710 + int32_t width, 1.711 + int32_t height, 1.712 + SkBitmap* scaled) { 1.713 + SkAutoMutexAcquire am(gMutex); 1.714 + return get_cache()->findAndLock(pixelGenerationID, width, height, scaled); 1.715 +} 1.716 + 1.717 +SkScaledImageCache::ID* SkScaledImageCache::AddAndLock( 1.718 + uint32_t pixelGenerationID, 1.719 + int32_t width, 1.720 + int32_t height, 1.721 + const SkBitmap& scaled) { 1.722 + SkAutoMutexAcquire am(gMutex); 1.723 + return get_cache()->addAndLock(pixelGenerationID, width, height, scaled); 1.724 +} 1.725 + 1.726 + 1.727 +SkScaledImageCache::ID* SkScaledImageCache::FindAndLock(const SkBitmap& orig, 1.728 + SkScalar scaleX, 1.729 + SkScalar scaleY, 1.730 + SkBitmap* scaled) { 1.731 + SkAutoMutexAcquire am(gMutex); 1.732 + return get_cache()->findAndLock(orig, scaleX, scaleY, scaled); 1.733 +} 1.734 + 1.735 +SkScaledImageCache::ID* SkScaledImageCache::FindAndLockMip(const SkBitmap& orig, 1.736 + SkMipMap const ** mip) { 1.737 + SkAutoMutexAcquire am(gMutex); 1.738 + return get_cache()->findAndLockMip(orig, mip); 1.739 +} 1.740 + 1.741 +SkScaledImageCache::ID* SkScaledImageCache::AddAndLock(const SkBitmap& orig, 1.742 + SkScalar scaleX, 1.743 + SkScalar scaleY, 1.744 + const SkBitmap& scaled) { 1.745 + SkAutoMutexAcquire am(gMutex); 1.746 + return get_cache()->addAndLock(orig, scaleX, scaleY, scaled); 1.747 +} 1.748 + 1.749 +SkScaledImageCache::ID* SkScaledImageCache::AddAndLockMip(const SkBitmap& orig, 1.750 + const SkMipMap* mip) { 1.751 + SkAutoMutexAcquire am(gMutex); 1.752 + return get_cache()->addAndLockMip(orig, mip); 1.753 +} 1.754 + 1.755 +void SkScaledImageCache::Unlock(SkScaledImageCache::ID* id) { 1.756 + SkAutoMutexAcquire am(gMutex); 1.757 + get_cache()->unlock(id); 1.758 + 1.759 +// get_cache()->dump(); 1.760 +} 1.761 + 1.762 +size_t SkScaledImageCache::GetBytesUsed() { 1.763 + SkAutoMutexAcquire am(gMutex); 1.764 + return get_cache()->getBytesUsed(); 1.765 +} 1.766 + 1.767 +size_t SkScaledImageCache::GetByteLimit() { 1.768 + SkAutoMutexAcquire am(gMutex); 1.769 + return get_cache()->getByteLimit(); 1.770 +} 1.771 + 1.772 +size_t SkScaledImageCache::SetByteLimit(size_t newLimit) { 1.773 + SkAutoMutexAcquire am(gMutex); 1.774 + return get_cache()->setByteLimit(newLimit); 1.775 +} 1.776 + 1.777 +SkBitmap::Allocator* SkScaledImageCache::GetAllocator() { 1.778 + SkAutoMutexAcquire am(gMutex); 1.779 + return get_cache()->allocator(); 1.780 +} 1.781 + 1.782 +void SkScaledImageCache::Dump() { 1.783 + SkAutoMutexAcquire am(gMutex); 1.784 + get_cache()->dump(); 1.785 +} 1.786 + 1.787 +/////////////////////////////////////////////////////////////////////////////// 1.788 + 1.789 +#include "SkGraphics.h" 1.790 + 1.791 +size_t SkGraphics::GetImageCacheBytesUsed() { 1.792 + return SkScaledImageCache::GetBytesUsed(); 1.793 +} 1.794 + 1.795 +size_t SkGraphics::GetImageCacheByteLimit() { 1.796 + return SkScaledImageCache::GetByteLimit(); 1.797 +} 1.798 + 1.799 +size_t SkGraphics::SetImageCacheByteLimit(size_t newLimit) { 1.800 + return SkScaledImageCache::SetByteLimit(newLimit); 1.801 +}