Home | History | Annotate | Download | only in images
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "SkImageRefPool.h"
      9 #include "SkImageRef.h"
     10 #include "SkThread.h"
     11 
     12 SkImageRefPool::SkImageRefPool() {
     13     fRAMBudget = 0; // means no explicit limit
     14     fRAMUsed = 0;
     15     fCount = 0;
     16     fHead = fTail = NULL;
     17 }
     18 
     19 SkImageRefPool::~SkImageRefPool() {
     20     //    SkASSERT(NULL == fHead);
     21 }
     22 
     23 void SkImageRefPool::setRAMBudget(size_t size) {
     24     if (fRAMBudget != size) {
     25         fRAMBudget = size;
     26         this->purgeIfNeeded();
     27     }
     28 }
     29 
     30 void SkImageRefPool::justAddedPixels(SkImageRef* ref) {
     31 #ifdef DUMP_IMAGEREF_LIFECYCLE
     32     SkDebugf("=== ImagePool: add pixels %s [%d %d %d] bytes=%d heap=%d\n",
     33              ref->getURI(),
     34              ref->fBitmap.width(), ref->fBitmap.height(),
     35              ref->fBitmap.bytesPerPixel(),
     36              ref->fBitmap.getSize(), (int)fRAMUsed);
     37 #endif
     38     fRAMUsed += ref->ramUsed();
     39     this->purgeIfNeeded();
     40 }
     41 
     42 void SkImageRefPool::canLosePixels(SkImageRef* ref) {
     43     // the refs near fHead have recently been released (used)
     44     // if we purge, we purge from the tail
     45     this->detach(ref);
     46     this->addToHead(ref);
     47     this->purgeIfNeeded();
     48 }
     49 
     50 void SkImageRefPool::purgeIfNeeded() {
     51     // do nothing if we have a zero-budget (i.e. unlimited)
     52     if (fRAMBudget != 0) {
     53         this->setRAMUsed(fRAMBudget);
     54     }
     55 }
     56 
     57 void SkImageRefPool::setRAMUsed(size_t limit) {
     58     SkImageRef* ref = fTail;
     59 
     60     while (NULL != ref && fRAMUsed > limit) {
     61         // only purge it if its pixels are unlocked
     62         if (!ref->isLocked() && ref->fBitmap.getPixels()) {
     63             size_t size = ref->ramUsed();
     64             SkASSERT(size <= fRAMUsed);
     65             fRAMUsed -= size;
     66 
     67 #ifdef DUMP_IMAGEREF_LIFECYCLE
     68             SkDebugf("=== ImagePool: purge %s [%d %d %d] bytes=%d heap=%d\n",
     69                      ref->getURI(),
     70                      ref->fBitmap.width(), ref->fBitmap.height(),
     71                      ref->fBitmap.bytesPerPixel(),
     72                      (int)size, (int)fRAMUsed);
     73 #endif
     74 
     75             // remember the bitmap config (don't call reset),
     76             // just clear the pixel memory
     77             ref->fBitmap.setPixels(NULL);
     78             SkASSERT(NULL == ref->fBitmap.getPixels());
     79         }
     80         ref = ref->fPrev;
     81     }
     82 }
     83 
     84 ///////////////////////////////////////////////////////////////////////////////
     85 
     86 void SkImageRefPool::addToHead(SkImageRef* ref) {
     87     ref->fNext = fHead;
     88     ref->fPrev = NULL;
     89 
     90     if (fHead) {
     91         SkASSERT(NULL == fHead->fPrev);
     92         fHead->fPrev = ref;
     93     }
     94     fHead = ref;
     95 
     96     if (NULL == fTail) {
     97         fTail = ref;
     98     }
     99     fCount += 1;
    100     SkASSERT(computeCount() == fCount);
    101 
    102     fRAMUsed += ref->ramUsed();
    103 }
    104 
    105 void SkImageRefPool::addToTail(SkImageRef* ref) {
    106     ref->fNext = NULL;
    107     ref->fPrev = fTail;
    108 
    109     if (fTail) {
    110         SkASSERT(NULL == fTail->fNext);
    111         fTail->fNext = ref;
    112     }
    113     fTail = ref;
    114 
    115     if (NULL == fHead) {
    116         fHead = ref;
    117     }
    118     fCount += 1;
    119     SkASSERT(computeCount() == fCount);
    120 
    121     fRAMUsed += ref->ramUsed();
    122 }
    123 
    124 void SkImageRefPool::detach(SkImageRef* ref) {
    125     SkASSERT(fCount > 0);
    126 
    127     if (fHead == ref) {
    128         fHead = ref->fNext;
    129     }
    130     if (fTail == ref) {
    131         fTail = ref->fPrev;
    132     }
    133     if (ref->fPrev) {
    134         ref->fPrev->fNext = ref->fNext;
    135     }
    136     if (ref->fNext) {
    137         ref->fNext->fPrev = ref->fPrev;
    138     }
    139 
    140     ref->fNext = ref->fPrev = NULL;
    141 
    142     fCount -= 1;
    143     SkASSERT(computeCount() == fCount);
    144 
    145     SkASSERT(fRAMUsed >= ref->ramUsed());
    146     fRAMUsed -= ref->ramUsed();
    147 }
    148 
    149 int SkImageRefPool::computeCount() const {
    150     SkImageRef* ref = fHead;
    151     int count = 0;
    152 
    153     while (ref != NULL) {
    154         count += 1;
    155         ref = ref->fNext;
    156     }
    157 
    158 #ifdef SK_DEBUG
    159     ref = fTail;
    160     int count2 = 0;
    161 
    162     while (ref != NULL) {
    163         count2 += 1;
    164         ref = ref->fPrev;
    165     }
    166     SkASSERT(count2 == count);
    167 #endif
    168 
    169     return count;
    170 }
    171 
    172 ///////////////////////////////////////////////////////////////////////////////
    173 
    174 #include "SkStream.h"
    175 
    176 void SkImageRefPool::dump() const {
    177 #if defined(SK_DEBUG) || defined(DUMP_IMAGEREF_LIFECYCLE)
    178     SkDebugf("ImagePool dump: bugdet: %d used: %d count: %d\n",
    179              (int)fRAMBudget, (int)fRAMUsed, fCount);
    180 
    181     SkImageRef* ref = fHead;
    182 
    183     while (ref != NULL) {
    184         SkDebugf("  [%3d %3d %d] ram=%d data=%d locked=%d %s\n", ref->fBitmap.width(),
    185                  ref->fBitmap.height(), ref->fBitmap.config(),
    186                  ref->ramUsed(), (int)ref->fStream->getLength(),
    187                  ref->isLocked(), ref->getURI());
    188 
    189         ref = ref->fNext;
    190     }
    191 #endif
    192 }
    193