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