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

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

Issue 511283002: rename ScaledImageCache to ResourceCache (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: rebase Created 6 years, 3 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
« no previous file with comments | « src/core/SkScaledImageCache.h ('k') | tests/CachedDecodingPixelRefTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkChecksum.h"
9 #include "SkScaledImageCache.h"
10 #include "SkMipMap.h"
11 #include "SkPixelRef.h"
12
13 // This can be defined by the caller's build system
14 //#define SK_USE_DISCARDABLE_SCALEDIMAGECACHE
15
16 #ifndef SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT
17 # define SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT 1024
18 #endif
19
20 #ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT
21 #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024)
22 #endif
23
24 void SkScaledImageCache::Key::init(size_t length) {
25 SkASSERT(SkAlign4(length) == length);
26 // 2 is fCount32 and fHash
27 fCount32 = SkToS32(2 + (length >> 2));
28 // skip both of our fields whe computing the murmur
29 fHash = SkChecksum::Murmur3(this->as32() + 2, (fCount32 - 2) << 2);
30 }
31
32 #include "SkTDynamicHash.h"
33
34 class SkScaledImageCache::Hash :
35 public SkTDynamicHash<SkScaledImageCache::Rec, SkScaledImageCache::Key> {};
36
37
38 ///////////////////////////////////////////////////////////////////////////////
39
40 // experimental hash to speed things up
41 #define USE_HASH
42
43 #if !defined(USE_HASH)
44 static inline SkScaledImageCache::Rec* find_rec_in_list(
45 SkScaledImageCache::Rec* head, const Key & key) {
46 SkScaledImageCache::Rec* rec = head;
47 while ((rec != NULL) && (rec->fKey != key)) {
48 rec = rec->fNext;
49 }
50 return rec;
51 }
52 #endif
53
54 void SkScaledImageCache::init() {
55 fHead = NULL;
56 fTail = NULL;
57 #ifdef USE_HASH
58 fHash = new Hash;
59 #else
60 fHash = NULL;
61 #endif
62 fTotalBytesUsed = 0;
63 fCount = 0;
64 fSingleAllocationByteLimit = 0;
65 fAllocator = NULL;
66
67 // One of these should be explicit set by the caller after we return.
68 fTotalByteLimit = 0;
69 fDiscardableFactory = NULL;
70 }
71
72 #include "SkDiscardableMemory.h"
73
74 class SkOneShotDiscardablePixelRef : public SkPixelRef {
75 public:
76 SK_DECLARE_INST_COUNT(SkOneShotDiscardablePixelRef)
77 // Ownership of the discardablememory is transfered to the pixelref
78 SkOneShotDiscardablePixelRef(const SkImageInfo&, SkDiscardableMemory*, size_ t rowBytes);
79 ~SkOneShotDiscardablePixelRef();
80
81 protected:
82 virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE;
83 virtual void onUnlockPixels() SK_OVERRIDE;
84 virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE;
85
86 private:
87 SkDiscardableMemory* fDM;
88 size_t fRB;
89 bool fFirstTime;
90
91 typedef SkPixelRef INHERITED;
92 };
93
94 SkOneShotDiscardablePixelRef::SkOneShotDiscardablePixelRef(const SkImageInfo& in fo,
95 SkDiscardableMemory* dm,
96 size_t rowBytes)
97 : INHERITED(info)
98 , fDM(dm)
99 , fRB(rowBytes)
100 {
101 SkASSERT(dm->data());
102 fFirstTime = true;
103 }
104
105 SkOneShotDiscardablePixelRef::~SkOneShotDiscardablePixelRef() {
106 SkDELETE(fDM);
107 }
108
109 bool SkOneShotDiscardablePixelRef::onNewLockPixels(LockRec* rec) {
110 if (fFirstTime) {
111 // we're already locked
112 SkASSERT(fDM->data());
113 fFirstTime = false;
114 goto SUCCESS;
115 }
116
117 // A previous call to onUnlock may have deleted our DM, so check for that
118 if (NULL == fDM) {
119 return false;
120 }
121
122 if (!fDM->lock()) {
123 // since it failed, we delete it now, to free-up the resource
124 delete fDM;
125 fDM = NULL;
126 return false;
127 }
128
129 SUCCESS:
130 rec->fPixels = fDM->data();
131 rec->fColorTable = NULL;
132 rec->fRowBytes = fRB;
133 return true;
134 }
135
136 void SkOneShotDiscardablePixelRef::onUnlockPixels() {
137 SkASSERT(!fFirstTime);
138 fDM->unlock();
139 }
140
141 size_t SkOneShotDiscardablePixelRef::getAllocatedSizeInBytes() const {
142 return this->info().getSafeSize(fRB);
143 }
144
145 class SkScaledImageCacheDiscardableAllocator : public SkBitmap::Allocator {
146 public:
147 SkScaledImageCacheDiscardableAllocator(
148 SkScaledImageCache::DiscardableFactory factory) {
149 SkASSERT(factory);
150 fFactory = factory;
151 }
152
153 virtual bool allocPixelRef(SkBitmap*, SkColorTable*) SK_OVERRIDE;
154
155 private:
156 SkScaledImageCache::DiscardableFactory fFactory;
157 };
158
159 bool SkScaledImageCacheDiscardableAllocator::allocPixelRef(SkBitmap* bitmap,
160 SkColorTable* ctable) {
161 size_t size = bitmap->getSize();
162 uint64_t size64 = bitmap->computeSize64();
163 if (0 == size || size64 > (uint64_t)size) {
164 return false;
165 }
166
167 SkDiscardableMemory* dm = fFactory(size);
168 if (NULL == dm) {
169 return false;
170 }
171
172 // can we relax this?
173 if (kN32_SkColorType != bitmap->colorType()) {
174 return false;
175 }
176
177 SkImageInfo info = bitmap->info();
178 bitmap->setPixelRef(SkNEW_ARGS(SkOneShotDiscardablePixelRef,
179 (info, dm, bitmap->rowBytes())))->unref();
180 bitmap->lockPixels();
181 return bitmap->readyToDraw();
182 }
183
184 SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) {
185 this->init();
186 fDiscardableFactory = factory;
187
188 fAllocator = SkNEW_ARGS(SkScaledImageCacheDiscardableAllocator, (factory));
189 }
190
191 SkScaledImageCache::SkScaledImageCache(size_t byteLimit) {
192 this->init();
193 fTotalByteLimit = byteLimit;
194 }
195
196 SkScaledImageCache::~SkScaledImageCache() {
197 SkSafeUnref(fAllocator);
198
199 Rec* rec = fHead;
200 while (rec) {
201 Rec* next = rec->fNext;
202 SkDELETE(rec);
203 rec = next;
204 }
205 delete fHash;
206 }
207
208 ////////////////////////////////////////////////////////////////////////////////
209
210 const SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const Key& key) {
211 #ifdef USE_HASH
212 Rec* rec = fHash->find(key);
213 #else
214 Rec* rec = find_rec_in_list(fHead, key);
215 #endif
216 if (rec) {
217 this->moveToHead(rec); // for our LRU
218 rec->fLockCount += 1;
219 }
220 return rec;
221 }
222
223 const SkScaledImageCache::Rec* SkScaledImageCache::addAndLock(Rec* rec) {
224 SkASSERT(rec);
225 // See if we already have this key (racy inserts, etc.)
226 const Rec* existing = this->findAndLock(rec->getKey());
227 if (NULL != existing) {
228 SkDELETE(rec);
229 return existing;
230 }
231
232 this->addToHead(rec);
233 SkASSERT(1 == rec->fLockCount);
234 #ifdef USE_HASH
235 SkASSERT(fHash);
236 fHash->add(rec);
237 #endif
238 // We may (now) be overbudget, so see if we need to purge something.
239 this->purgeAsNeeded();
240 return rec;
241 }
242
243 void SkScaledImageCache::add(Rec* rec) {
244 SkASSERT(rec);
245 // See if we already have this key (racy inserts, etc.)
246 const Rec* existing = this->findAndLock(rec->getKey());
247 if (NULL != existing) {
248 SkDELETE(rec);
249 this->unlock(existing);
250 return;
251 }
252
253 this->addToHead(rec);
254 SkASSERT(1 == rec->fLockCount);
255 #ifdef USE_HASH
256 SkASSERT(fHash);
257 fHash->add(rec);
258 #endif
259 this->unlock(rec);
260 }
261
262 void SkScaledImageCache::unlock(SkScaledImageCache::ID id) {
263 SkASSERT(id);
264
265 #ifdef SK_DEBUG
266 {
267 bool found = false;
268 Rec* rec = fHead;
269 while (rec != NULL) {
270 if (rec == id) {
271 found = true;
272 break;
273 }
274 rec = rec->fNext;
275 }
276 SkASSERT(found);
277 }
278 #endif
279 const Rec* rec = id;
280 SkASSERT(rec->fLockCount > 0);
281 // We're under our lock, and we're the only possible mutator, so unconsting is fine.
282 const_cast<Rec*>(rec)->fLockCount -= 1;
283
284 // we may have been over-budget, but now have released something, so check
285 // if we should purge.
286 if (0 == rec->fLockCount) {
287 this->purgeAsNeeded();
288 }
289 }
290
291 void SkScaledImageCache::purgeAsNeeded() {
292 size_t byteLimit;
293 int countLimit;
294
295 if (fDiscardableFactory) {
296 countLimit = SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT;
297 byteLimit = SK_MaxU32; // no limit based on bytes
298 } else {
299 countLimit = SK_MaxS32; // no limit based on count
300 byteLimit = fTotalByteLimit;
301 }
302
303 size_t bytesUsed = fTotalBytesUsed;
304 int countUsed = fCount;
305
306 Rec* rec = fTail;
307 while (rec) {
308 if (bytesUsed < byteLimit && countUsed < countLimit) {
309 break;
310 }
311
312 Rec* prev = rec->fPrev;
313 if (0 == rec->fLockCount) {
314 size_t used = rec->bytesUsed();
315 SkASSERT(used <= bytesUsed);
316 this->detach(rec);
317 #ifdef USE_HASH
318 fHash->remove(rec->getKey());
319 #endif
320
321 SkDELETE(rec);
322
323 bytesUsed -= used;
324 countUsed -= 1;
325 }
326 rec = prev;
327 }
328
329 fTotalBytesUsed = bytesUsed;
330 fCount = countUsed;
331 }
332
333 size_t SkScaledImageCache::setTotalByteLimit(size_t newLimit) {
334 size_t prevLimit = fTotalByteLimit;
335 fTotalByteLimit = newLimit;
336 if (newLimit < prevLimit) {
337 this->purgeAsNeeded();
338 }
339 return prevLimit;
340 }
341
342 ///////////////////////////////////////////////////////////////////////////////
343
344 void SkScaledImageCache::detach(Rec* rec) {
345 Rec* prev = rec->fPrev;
346 Rec* next = rec->fNext;
347
348 if (!prev) {
349 SkASSERT(fHead == rec);
350 fHead = next;
351 } else {
352 prev->fNext = next;
353 }
354
355 if (!next) {
356 fTail = prev;
357 } else {
358 next->fPrev = prev;
359 }
360
361 rec->fNext = rec->fPrev = NULL;
362 }
363
364 void SkScaledImageCache::moveToHead(Rec* rec) {
365 if (fHead == rec) {
366 return;
367 }
368
369 SkASSERT(fHead);
370 SkASSERT(fTail);
371
372 this->validate();
373
374 this->detach(rec);
375
376 fHead->fPrev = rec;
377 rec->fNext = fHead;
378 fHead = rec;
379
380 this->validate();
381 }
382
383 void SkScaledImageCache::addToHead(Rec* rec) {
384 this->validate();
385
386 rec->fPrev = NULL;
387 rec->fNext = fHead;
388 if (fHead) {
389 fHead->fPrev = rec;
390 }
391 fHead = rec;
392 if (!fTail) {
393 fTail = rec;
394 }
395 fTotalBytesUsed += rec->bytesUsed();
396 fCount += 1;
397
398 this->validate();
399 }
400
401 ///////////////////////////////////////////////////////////////////////////////
402
403 #ifdef SK_DEBUG
404 void SkScaledImageCache::validate() const {
405 if (NULL == fHead) {
406 SkASSERT(NULL == fTail);
407 SkASSERT(0 == fTotalBytesUsed);
408 return;
409 }
410
411 if (fHead == fTail) {
412 SkASSERT(NULL == fHead->fPrev);
413 SkASSERT(NULL == fHead->fNext);
414 SkASSERT(fHead->bytesUsed() == fTotalBytesUsed);
415 return;
416 }
417
418 SkASSERT(NULL == fHead->fPrev);
419 SkASSERT(NULL != fHead->fNext);
420 SkASSERT(NULL == fTail->fNext);
421 SkASSERT(NULL != fTail->fPrev);
422
423 size_t used = 0;
424 int count = 0;
425 const Rec* rec = fHead;
426 while (rec) {
427 count += 1;
428 used += rec->bytesUsed();
429 SkASSERT(used <= fTotalBytesUsed);
430 rec = rec->fNext;
431 }
432 SkASSERT(fCount == count);
433
434 rec = fTail;
435 while (rec) {
436 SkASSERT(count > 0);
437 count -= 1;
438 SkASSERT(used >= rec->bytesUsed());
439 used -= rec->bytesUsed();
440 rec = rec->fPrev;
441 }
442
443 SkASSERT(0 == count);
444 SkASSERT(0 == used);
445 }
446 #endif
447
448 void SkScaledImageCache::dump() const {
449 this->validate();
450
451 const Rec* rec = fHead;
452 int locked = 0;
453 while (rec) {
454 locked += rec->fLockCount > 0;
455 rec = rec->fNext;
456 }
457
458 SkDebugf("SkScaledImageCache: count=%d bytes=%d locked=%d %s\n",
459 fCount, fTotalBytesUsed, locked,
460 fDiscardableFactory ? "discardable" : "malloc");
461 }
462
463 size_t SkScaledImageCache::setSingleAllocationByteLimit(size_t newLimit) {
464 size_t oldLimit = fSingleAllocationByteLimit;
465 fSingleAllocationByteLimit = newLimit;
466 return oldLimit;
467 }
468
469 size_t SkScaledImageCache::getSingleAllocationByteLimit() const {
470 return fSingleAllocationByteLimit;
471 }
472
473 ///////////////////////////////////////////////////////////////////////////////
474
475 #include "SkThread.h"
476
477 SK_DECLARE_STATIC_MUTEX(gMutex);
478 static SkScaledImageCache* gScaledImageCache = NULL;
479 static void cleanup_gScaledImageCache() {
480 // We'll clean this up in our own tests, but disable for clients.
481 // Chrome seems to have funky multi-process things going on in unit tests th at
482 // makes this unsafe to delete when the main process atexit()s.
483 // SkLazyPtr does the same sort of thing.
484 #if SK_DEVELOPER
485 SkDELETE(gScaledImageCache);
486 #endif
487 }
488
489 /** Must hold gMutex when calling. */
490 static SkScaledImageCache* get_cache() {
491 // gMutex is always held when this is called, so we don't need to be fancy i n here.
492 gMutex.assertHeld();
493 if (NULL == gScaledImageCache) {
494 #ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE
495 gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory: :Create));
496 #else
497 gScaledImageCache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CAC HE_LIMIT));
498 #endif
499 atexit(cleanup_gScaledImageCache);
500 }
501 return gScaledImageCache;
502 }
503
504 void SkScaledImageCache::Unlock(SkScaledImageCache::ID id) {
505 SkAutoMutexAcquire am(gMutex);
506 get_cache()->unlock(id);
507
508 // get_cache()->dump();
509 }
510
511 size_t SkScaledImageCache::GetTotalBytesUsed() {
512 SkAutoMutexAcquire am(gMutex);
513 return get_cache()->getTotalBytesUsed();
514 }
515
516 size_t SkScaledImageCache::GetTotalByteLimit() {
517 SkAutoMutexAcquire am(gMutex);
518 return get_cache()->getTotalByteLimit();
519 }
520
521 size_t SkScaledImageCache::SetTotalByteLimit(size_t newLimit) {
522 SkAutoMutexAcquire am(gMutex);
523 return get_cache()->setTotalByteLimit(newLimit);
524 }
525
526 SkBitmap::Allocator* SkScaledImageCache::GetAllocator() {
527 SkAutoMutexAcquire am(gMutex);
528 return get_cache()->allocator();
529 }
530
531 void SkScaledImageCache::Dump() {
532 SkAutoMutexAcquire am(gMutex);
533 get_cache()->dump();
534 }
535
536 size_t SkScaledImageCache::SetSingleAllocationByteLimit(size_t size) {
537 SkAutoMutexAcquire am(gMutex);
538 return get_cache()->setSingleAllocationByteLimit(size);
539 }
540
541 size_t SkScaledImageCache::GetSingleAllocationByteLimit() {
542 SkAutoMutexAcquire am(gMutex);
543 return get_cache()->getSingleAllocationByteLimit();
544 }
545
546 const SkScaledImageCache::Rec* SkScaledImageCache::FindAndLock(const Key& key) {
547 SkAutoMutexAcquire am(gMutex);
548 return get_cache()->findAndLock(key);
549 }
550
551 const SkScaledImageCache::Rec* SkScaledImageCache::AddAndLock(Rec* rec) {
552 SkAutoMutexAcquire am(gMutex);
553 return get_cache()->addAndLock(rec);
554 }
555
556 void SkScaledImageCache::Add(Rec* rec) {
557 SkAutoMutexAcquire am(gMutex);
558 get_cache()->add(rec);
559 }
560
561 ///////////////////////////////////////////////////////////////////////////////
562
563 #include "SkGraphics.h"
564
565 size_t SkGraphics::GetImageCacheTotalBytesUsed() {
566 return SkScaledImageCache::GetTotalBytesUsed();
567 }
568
569 size_t SkGraphics::GetImageCacheTotalByteLimit() {
570 return SkScaledImageCache::GetTotalByteLimit();
571 }
572
573 size_t SkGraphics::SetImageCacheTotalByteLimit(size_t newLimit) {
574 return SkScaledImageCache::SetTotalByteLimit(newLimit);
575 }
576
577 size_t SkGraphics::GetImageCacheSingleAllocationByteLimit() {
578 return SkScaledImageCache::GetSingleAllocationByteLimit();
579 }
580
581 size_t SkGraphics::SetImageCacheSingleAllocationByteLimit(size_t newLimit) {
582 return SkScaledImageCache::SetSingleAllocationByteLimit(newLimit);
583 }
584
OLDNEW
« no previous file with comments | « src/core/SkScaledImageCache.h ('k') | tests/CachedDecodingPixelRefTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698